spring-boot與日志
使用slf4j
如何讓系統(tǒng)中所有的日志都統(tǒng)一到slf4j
- 將系統(tǒng)中其他日志框架先排除出去馍资。
- 用中間包來替換原有的日志框架。
- 我們導(dǎo)入slf4j其他的實現(xiàn)撕捍。
spring-boot的日志依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>
總結(jié):
- spring-boot底層選用的是slf4j+logback進行日志記錄。
- spring-boot把其他的日志都替換成了slf4j泣洞。
- 如果我們要引入其他框架忧风,需要把默認的日志依賴移除掉。
spring-boot的日志使用
導(dǎo)入slf4j的jar和logback的實現(xiàn)jar
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggerApplicationTests {
@Test
public void contextLoads() {
Logger logger = LoggerFactory.getLogger(LoggerApplicationTests.class);
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
日志級別
spring-boot默認日志級別是info
1. trace
2. debug
3. info
4. warn
5. error
日志默認配置修改
日志輸出格式:
%d:表示日期時間球凰,
%thread:表示線程名狮腿,
%‐5level:級別從左顯示5個字符寬度
%logger{50}:表示logger名字最長50個字符,否則按照句點分割呕诉。
%msg:日志消息缘厢,
%n:是換行符
例子:
%d{yyyy‐MM‐dd HH:mm:ss} [%thread] %-5level %logger- %msg%n
控制臺:
//修改默認日志級別,level后面跟著包名
logging.level.com.bafan.springboot.logger=trace
//修改控制臺
logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
指定文件輸出:
在實際的項目開發(fā)中甩挫,我們習(xí)慣將日志輸出到服務(wù)器的某個文件下
- 需要將日志的配置文件放在類路徑下(spring-boot就不使用他默認的配置了)贴硫。
- logback.xml:直接被日志框架識別。
- logback-spring.xml:日志框架不直接加載日志的配置項伊者,由spring-boot解析日志配置夜畴,可以使用spring-boot的高級profile功能。(推薦)删壮。(<springProfile name="dev">可以根據(jù)環(huán)境來決定功能)
spring-boot識別logback.xml文件
1--LoggingApplicationListener的initialize方法
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
(new LoggingSystemProperties(environment)).apply();
LogFile logFile = LogFile.get(environment);
if (logFile != null) {
logFile.applyToSystemProperties();
}
this.initializeEarlyLoggingLevel(environment);
//進入
this.initializeSystem(environment, this.loggingSystem, logFile);
this.initializeFinalLoggingLevels(environment, this.loggingSystem);
this.registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
2--LoggingApplicationListener的initializeSystem方法
private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {
LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
String logConfig = environment.getProperty("logging.config");
if (this.ignoreLogConfig(logConfig)) {
//進入
system.initialize(initializationContext, (String)null, logFile);
} else {
try {
ResourceUtils.getURL(logConfig).openStream().close();
system.initialize(initializationContext, logConfig, logFile);
} catch (Exception var7) {
System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
var7.printStackTrace(System.err);
throw new IllegalStateException(var7);
}
}
}
3--LogbackLoggingSystem的initialize方法
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
LoggerContext loggerContext = this.getLoggerContext();
if (!this.isAlreadyInitialized(loggerContext)) {
//調(diào)用父類的初始化方法
super.initialize(initializationContext, configLocation, logFile);
loggerContext.getTurboFilterList().remove(FILTER);
this.markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty("logback.configurationFile"))) {
this.getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring 'logback.configurationFile' system property. Please use 'logging.config' instead.");
}
}
}
4--AbstractLoggingSystem的initialize方法
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
if (StringUtils.hasLength(configLocation)) {
this.initializeWithSpecificConfig(initializationContext, configLocation, logFile);
} else {
//進入
this.initializeWithConventions(initializationContext, logFile);
}
}
5--AbstractLoggingSystem的initializeWithConventions方法
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
//查找自己的配置(logback.xml)
String config = this.getSelfInitializationConfig();
if (config != null && logFile == null) {
this.reinitialize(initializationContext);
} else { //如果沒有找到贪绘,就去找spring的文件
if (config == null) {
//查找spring的配置(logback-spring.xml)
config = this.getSpringInitializationConfig();
}
if (config != null) {
this.loadConfiguration(initializationContext, config, logFile);
} else { //如果都沒有找到,只使用properties默認的配置
this.loadDefaults(initializationContext, logFile);
}
}
}
6--AbstractLoggingSystem的getSelfInitializationConfig方法央碟,執(zhí)行結(jié)束后到7
protected String getSelfInitializationConfig() {
//獲取spring-boot標準的配置
return this.findConfig(this.getStandardConfigLocations());
}
protected String[] getStandardConfigLocations() {
return new String[]{"logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml"};
}
7--AbstractLoggingSystem的findConfig方法税灌,執(zhí)行結(jié)束后到5
private String findConfig(String[] locations) {
String[] var2 = locations;
int var3 = locations.length;
//如果能夠找到配置文件的位置均函,則返回配置文件位置,否則返回null
for(int var4 = 0; var4 < var3; ++var4) {
String location = var2[var4];
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
8--AbstractLoggingSystem的getSpringConfigLocations方法菱涤,執(zhí)行結(jié)束后到7
protected String[] getSpringConfigLocations() {
String[] locations = this.getStandardConfigLocations();
for(int i = 0; i < locations.length; ++i) {
//加上-spring后綴再在跟路徑下查找
String extension = StringUtils.getFilenameExtension(locations[i]);
locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring." + extension;
}
return locations;
}
logback常用配置
1--根節(jié)點configuration
- 通常不加任何屬性苞也。
2--configuration的子節(jié)點
2.1 property
//用來定義變量
<property name="FILE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %c{35} %M %L - %msg%n"/>
...
<encoder>
<pattern>${FILE_PATTERN}</pattern>
</encoder>
2.2 logger
- name:用來指定受此logger約束的某一個包或者具體的某一個類。
- level:用來打印日志級別粘秆。(root<append<logger)
- additivity:是否向上級傳遞打印信息如迟,默認是true,項目中都用false
<logger name="com.mogujie.raptor" level="@root.log.level@" additivity="false">
<appender-ref ref="RAPTOR_FILE"/>
</logger>
2.3 root
- 也屬于logger標簽攻走,只有一個屬性殷勘,定義日志級別,默認是全路徑昔搂。
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
3--appender和它的子節(jié)點
- appender是configuration的子節(jié)點玲销。
- name:指定appender名稱,class指定appender的全限名摘符。
3.1 ConsoleAppender
- 控制臺日志
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
3.2 RollingFileAppender
滾動日志文件:先將日志記錄到指定文件贤斜,當(dāng)符合某個條件的時候,將日志記錄到 其它文件逛裤。FileAppender沒有滾動功能瘩绒,要么追加要么覆蓋,項目中幾乎不用带族。
- file:寫入文件的名字草讶。
- append:默認是true、追加炉菲;false是覆蓋堕战。
- encoder:對記錄事件進行格式化。一是把日志信息轉(zhuǎn)成字節(jié)數(shù)組拍霜,二是把字節(jié)數(shù)組寫入輸出流嘱丢。
- rollingPolicy:發(fā)生滾動時,涉及文件移動和重命名祠饺。
rollingPolicy:
- TimeBasedRollingPolicy:最常用的滾動方式越驻,根據(jù)時間制定滾動策略,既負責(zé)滾動道偷,也負責(zé)觸發(fā)滾動缀旁。
- fileNamePattern:包含文件名及“%d”轉(zhuǎn)換符。
- maxHistory:保留最大時間勺鸦,根據(jù)fileNamePattern的時間決定單位是年月日并巍。
- timeBasedFileNamingAndTriggeringPolicy:當(dāng)文件大小超過多少時觸發(fā)滾動,里面配置maxFileSize换途,例如500MB懊渡。
<appender name="errorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_PATTERN}</pattern>
</encoder>
<Encoding>UTF-8</Encoding>
<file>${CATALINA_APPLOG}/finance_mall_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${CATALINA_APPLOG}/finance_mall_error_%d{yyyy_MM_dd}-%i.log</fileNamePattern>
<MaxHistory>10</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
4. filter
屬于appender下的標簽刽射,一般用于日志級別過濾
- level:日志級別
- onMatch:如果匹配上,接受(ACCEPT)
- onMismatch:如果沒有匹配上剃执,拒絕(DENY)
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>