问题:
logback和log4j一样,属于日志输出系统。当你使用logback的时候,你是否遇到过当你配置了INFO日志级别之后,输出的只有一种级别的日志(如:INFO),warn、error更高级别的日志没有输出,这是为何呢?我在使用SpringBoot中的logback就遇到了这个问题。
原因:
我的配置文件logback.xml是这样写的:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台打印日志的相关配置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志格式 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - [%class:%line] - %m%n</pattern>
</encoder>
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 基于dubug处理日志:具体控制台或者文件对日志级别的处理还要看所在appender配置的filter,如果没有配置filter,则使用root配置 -->
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
结果发现日志打印只有INFO级别,高于INFO或者低于INFO的都没有打印。我们知道很多时候我们要求是高于INFO的(如:WARN、ERROR)都要打印的。问题在哪里呢?(问题就在于网上拷贝了被人的xml配置文件)
查看filter:ch.qos.logback.classic.filter.LevelFilter类
public class LevelFilter extends AbstractMatcherFilter<ILoggingEvent> {
Level level;
@Override
public FilterReply decide(ILoggingEvent event) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
//*****问题就在这里*****//
if (event.getLevel().equals(level)) {
return onMatch;
} else {
return onMismatch;
}
}
public void setLevel(Level level) {
this.level = level;
}
public void start() {
if (this.level != null) {
super.start();
}
}
}
我们发现代码中只要日志级别level不是绝对相等(.equals)就判断为onMismatch,这显然是不符合要求的。
怎么解决呢?
解决方案:
查看ch.qos.logback.classic.filter包下还有另一个filter : ThresholdFilter,使用这个作为过滤器,不需要配置<onMatch>和<onMismatch>,如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台打印日志的相关配置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志格式 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - [%class:%line] - %m%n</pattern>
</encoder>
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- 基于dubug处理日志:具体控制台或者文件对日志级别的处理还要看所在appender配置的filter,如果没有配置filter,则使用root配置 -->
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
测试结果满足要求。
再看这个ThresholdFilter代码:
public class ThresholdFilter extends Filter<ILoggingEvent> {
Level level;
@Override
public FilterReply decide(ILoggingEvent event) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
//这里是问题的关键
if (event.getLevel().isGreaterOrEqual(level)) {
return FilterReply.NEUTRAL;
} else {
return FilterReply.DENY;
}
}
public void setLevel(String level) {
this.level = Level.toLevel(level);
}
public void start() {
if (this.level != null) {
super.start();
}
}
}
我们发现ThresholdFilter中level用了isGreaterOrEqual(),这是满足要求的。
说明:
这里只是分享自己遇到的一个问题,并不是要说明LevelFilter有bug,或许这个filter是为了满足输出指定级别的日志,而不是高于某个级别的日志。因此当你想输出高于某个级别的日志的时候,建议你使用ThresholdFilter。
最后上传一个logback.xml配置文件,方便日后查阅
logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台打印日志的相关配置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志格式 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - [%class:%line] - %m%n</pattern>
</encoder>
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- 文件保存日志的相关配置 -->
<appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 保存日志文件的路径 -->
<file>D:/app_logs/SpringBoot-Logging.log</file>
<!-- 日志格式 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - [%class:%line] - %m%n</pattern>
</encoder>
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>SpringBoot-Logging.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 最大保存时间:30天-->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 文件保存日志的相关配置 -->
<appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 保存日志文件的路径 -->
<file>D:/app_logs/SpringBoot-Logging-error.log</file>
<!-- 日志格式 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - [%class:%line] - %m%n</pattern>
</encoder>
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>SpringBoot-Logging-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 最大保存时间:30天-->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 基于dubug处理日志:具体控制台或者文件对日志级别的处理还要看所在appender配置的filter,如果没有配置filter,则使用root配置 -->
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="INFO-OUT" />
<appender-ref ref="ERROR-OUT" />
</root>
</configuration>
author:蓝何忠
email:lanhezhong@163.com