spring boot 日志简介
spring boot只依赖 Commons Logging API,而不依赖其他日志(jul、logback、log4j)。
方法1
要想使用logback,必须引入jcl-over-slf4j
( 实现了 Commons Logging API),将jcl转接到slf4j。所有的spring boot starter都依赖了spring-boot-starter-web
,pom如下
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
</dependencies>
可以看到spring-boot-starter-logging
引入了logback,同时将log4j、jul都转接到slf4j,这就是为什么引入jcl-over-slf4j
就能使logback生效的原因。
方法2
除了上述操作,还有另外一个办法,根据spring boot 2.1.13
的文档说明,不用引入上述那么多的依赖,只要引入spring-boot-starter-web
即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如想修改日志级别,在application.properties
中设置logging.level
即可。
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
通过logging.file
修改日志文件位置。
spring boot 配置logback
类路径下新建logback.xml
或者logback-spring.xml
,推荐使用后者。
- logback.xml还是用logback-spring.xml?
-
根据,springboot中配置logback所说,logback.xml是标准的logback配置文件,但不支持spring boot logback扩展
-
logback-spring.xml可以使用springboot logback 扩展,支持spring profile、Spring Environment,也就是通常所说的能获取yml、properties中的值。
-
spring boot提供了logback的默认配置org/springframework/boot/logging/logback/base.xml
,除了base.xml还有defaults.xml、console-appender.xml、file-appender.xml,提供了log_pattern、consoleAppender、FileAppender,在自定义的logback-spring.xml中,都可以引入这些文件,加以利用,
<included>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</included>
defaults.xml
配置了tomcat、hibernate的日志级别,规定了控制台及文件的输出格式。
<included>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
</included>
console-appender.xml
使用了defaults.xml
规定的控制台输出格式。
<included>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
</included>
file-appender.xml
使用了defaults.xml
规定的文件输出格式,并会按照大小和时间分片,文件最大10M。
<included>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
<maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
</rollingPolicy>
</appender>
</included>
配置logback只输出到文件
新建logback-spring.xml
引入 file-appender.xml
,没有引入 console-appender.xml
,所以不会输出到控制台。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
开发环境输出到控制台、线上环境输出到文件
那么就可以使用logback-spring.xml中的springProfile来实现
<springProfile name="dev">
<root level="debug">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<springProfile name="!dev">
<root level="info">
<appender-ref ref="asyncFileAppender"/>
</root>
</springProfile>
logback不起作用,使用了其他日志
在实践中,往往遇到logback不起作用的情况,通过mvn dependency:tree
查看依赖,一般来说都是因为引入了其它日志实现(log4j、apache commons log)导致,控制台一般会有提示,这种情况,排除掉其他日志实现 即可。比如
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
问题
笔者在实践中,遇到了root配置的debug级别,过滤器目标级别是INFO,实际info、warn、error都输出的问题;
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
</filter>
</appender>
<springProfile name="dev">
<root level="debug">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
LevelFilter过滤器只有INFO级别才会匹配,这个从源码可以得知
ch.qos.logback.classic.filter.LevelFilter
public FilterReply decide(ILoggingEvent event) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
if (event.getLevel().equals(level)) {
return onMatch;
} else {
return onMismatch;
}
}
不禁想到info、warn等会产生mismatch,mistach采用的是NEUTRAL(中立),
ch.qos.logback.core.filter.AbstractMatcherFilter
protected FilterReply onMismatch = FilterReply.NEUTRAL;
查阅官方文档Filters,当结果是NEUTRAL时,如果没有下一个filter则正常输出,否则交给下一个filter处理,至此真相大白;
Filters are organized as an ordered list and are based on ternary
logic. The decide(ILoggingEvent event) method of each filter is called
in sequence. This method returns one of the FilterReply enumeration
values, i.e. one of DENY, NEUTRAL or ACCEPT. If the value returned by
decide() is DENY, then the log event is dropped immediately without
consulting the remaining filters. If the value returned is NEUTRAL,
then the next filter in the list is consulted. If there are no further
filters to consult, then the logging event is processed normally. If
the returned value is ACCEPT, then the logging event is processed
immediately skipping the invocation of the remaining filters.
要想自定义mismatch,添加onMismatch标签即可,这样配置就会只输出INFO级别;
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMismatch>DENY</onMismatch>
</filter>
除了LevelFilter过滤器,还有ch.qos.logback.classic.filter.ThresholdFilter
,这种是大于等于指定级别才会输出,这个可以从源码中得知。
ch.qos.logback.classic.filter.ThresholdFilter
public FilterReply decide(ILoggingEvent event) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
if (event.getLevel().isGreaterOrEqual(level)) {
//大于等于指定级别返回中立
return FilterReply.NEUTRAL;
} else {
return FilterReply.DENY;
}
}
总结
spring boot使用logback
- 引入
spring-boot-starter-web
- 如果只改变日志级别,在
application.properties
中配置logging.level
即可 - 细粒度的控制,新建
logback-spring.xml
,酌情引入defaults.xml
、console-appender.xml
、file-appender.xml
LevelFilter和ThresholdFilter
- LevelFilter只有等于指定级别才会输出
- ThresholdFilter大于等于指定级别才会输出