1. 程式人生 > >logback沒有輸出更高一級的日誌

logback沒有輸出更高一級的日誌

問題:

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]