logback沒有輸出更高一級的日誌
阿新 • • 發佈:2018-12-15
問題:
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。
author:藍何忠
email:[email protected]