1. 程式人生 > 其它 >logback1.3.x配置詳解與實踐

logback1.3.x配置詳解與實踐

前提

當前(2022-02前後)日誌框架logback的最新版本1.3.0已經更新到1.3.0-alpha14版本,此版本為非stable版本,相對於最新穩定版1.2.10來說,雖然slf4j-api版本升級了,但使用的API大體不變,對於XML配置來看提供了import標籤對於多appender來說可以簡化配置。鑑於軟體最新版本強迫症,這裡基於1.3.0-alpha14版本分析一下常用的logback配置項以及一些實踐經驗。

日誌等級

日誌等級的定義見Level類:

序號 日誌級別 備註
1 OFF Integer.MAX_VALUE 關閉日誌列印
2 TRACE 5000 -
3
DEBUG 10000 -
4 INFO 20000 -
5 WARN 30000 -
6 ERROR 40000 -
7 ALL Integer.MIN_VALUE 列印所有日誌

日誌等級的值越大,級別越高,級別由低到高(左到右)排列如下:

TRACE < DEBUG < INFO < WARN < ERROR

日誌等級一般會作為日誌事件的過濾條件或者查詢條件,在一些特定元件中,可以通過配置項去決定丟棄低級別的日誌事件或者忽略指定級別的日誌事件。

依賴引入

因為當前的1.3.0-alpha14版本太過"新",大部分主流框架尚未整合,如果要嚐鮮最好通過BOM全域性指定對應依賴的版本:

<!-- BOM -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.0-alpha6</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.0-alpha14</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.3.0-alpha14</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 依賴集合 -->
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
</dependencies>

logback.xml基本配置示例

1.2.x1.3.x提供的API基本沒有改變,並且1.3.x向前相容了舊的配置方式,提供了import標籤用於簡化class的指定:

  • 1.2.x(舊的配置方式)前的配置方式:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
  • 1.3.x可用的新配置方式:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <import class="ch.qos.logback.core.ConsoleAppender"/>
    <import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>

    <appender name="STDOUT" class="ConsoleAppender">
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

對於單個Appender配置來看,import標籤的引入看起來無法簡化配置,但是對於多Appender配置來看可以相對簡化class的指定,例如:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <property name="app" value="api-gateway"/>
    <property name="filename" value="server"/>

    <import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
    <import class="ch.qos.logback.core.rolling.RollingFileAppender"/>
    <import class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"/>
    <import class="ch.qos.logback.core.ConsoleAppender"/>
    <import class="ch.qos.logback.classic.AsyncAppender"/>
    <import class="ch.qos.logback.classic.filter.ThresholdFilter"/>
    <import class="cn.vlts.logback.IncludeLevelSetFilter"/>

    <appender name="INFO" class="RollingFileAppender">
        <file>/data/log-center/${app}/${filename}.log</file>
        <rollingPolicy class="TimeBasedRollingPolicy">
            <fileNamePattern>/data/log-center/${app}/${filename}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>14</maxHistory>
        </rollingPolicy>
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] ${app} - %msg%n</pattern>
        </encoder>
        <filter class="IncludeLevelSetFilter">
            <levels>INFO,WARN</levels>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="ERROR" class="RollingFileAppender">
        <file>/data/log-center/${app}/${filename}-error.log</file>
        <rollingPolicy class="TimeBasedRollingPolicy">
            <fileNamePattern>/data/log-center/${app}/${filename}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>14</maxHistory>
        </rollingPolicy>
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] ${app} - %msg%n</pattern>
        </encoder>
        <filter class="ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <appender name="STDOUT" class="ConsoleAppender">
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
         <filter class="ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>

    <appender name="ASYNC_INFO" class="AsyncAppender">
        <queueSize>1024</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="INFO"/>
    </appender>

    <appender name="ASYNC_ERROR" class="AsyncAppender">
        <queueSize>256</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="ERROR"/>
    </appender>
    
    <logger name="sun.rmi" level="error"/>
    <logger name="sun.net" level="error"/>
    <logger name="javax.management" level="error"/>
    <logger name="org.redisson" level="warn"/>
    <logger name="com.zaxxer" level="warn"/>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC_INFO"/>
        <appender-ref ref="ASYNC_ERROR"/>
    </root>
</configuration>

上面的配置是某個API閘道器的logback.xml配置示例,這裡用到了一個自定義Filter實現IncludeLevelSetFilter

// cn.vlts.logback.IncludeLevelSetFilter
public class IncludeLevelSetFilter extends AbstractMatcherFilter<ILoggingEvent> {

    private String levels;

    private Set<Level> levelSet;

    @Override
    public FilterReply decide(ILoggingEvent event) {
        return levelSet.contains(event.getLevel()) ? onMatch : onMismatch;
    }

    public void setLevels(String levels) {
        this.levels = levels;
        this.levelSet = Arrays.stream(levels.split(","))
                .map(item -> Level.toLevel(item, Level.INFO)).collect(Collectors.toSet());
    }

    @Override
    public void start() {
        if (Objects.nonNull(this.levels)) {
            super.start();
        }
    }
}

IncludeLevelSetFilter用於接受指定日誌級別集合的日誌記錄,如果有更加精細的日誌過濾條件(內建常用的LevelFilterThresholdFilter等無法滿足實際需求),可以自行實現ch.qos.logback.core.filter.Filter介面定製日誌事件過濾策略。這份檔案定義了五個appender,其中有2個用於非同步增強,核心appender3個:

  • STDOUTConsoleAppender,標準輸出同步日誌列印,級別為DEBUG或以上
  • ASYNC_INFOINFO):RollingFileAppender,非同步滾動檔案追加日誌列印,級別為INFO或者WARN,追加到檔案/data/log-center/api-gateway/server.log,歸檔檔案格式為/data/log-center/api-gateway/server-${yyyy-MM-dd}.log.${compression_suffix},歸檔檔案最多儲存14個副本
  • ASYNC_ERRORERROR):RollingFileAppender,非同步滾動檔案追加日誌列印,級別為ERROR,追加到檔案/data/log-center/api-gateway/server-error.log,歸檔檔案格式為/data/log-center/api-gateway/server-error-${yyyy-MM-dd}.log.${compression_suffix},歸檔檔案最多儲存14個副本

常用的Appender及其引數

常用的Appender有:

  • ConsoleAppender
  • FileAppender
  • RollingFileAppender
  • AsyncAppender

其中,RollingFileAppenderFileAppender的擴充套件(子類),現實場景中ConsoleAppenderRollingFileAppender的適用範圍更廣。從類繼承關係上看,ConsoleAppenderFileAppender都支援定義Encoder,最常用的Encoder實現就是PatternLayoutEncoder,用於定製日誌事件的最終輸出格式。關於Encoder,由於其引數格式太過靈活,引數眾多,限於篇幅本文不會展開介紹

ConsoleAppender

ConsoleAppender用於追加日誌到控制檯,對於Java應用來說就是追加到System.out或者System.errConsoleAppender支援的引數如下:

引數 型別 預設值 描述
encoder ch.qos.logback.core.encoder.Encoder PatternLayoutEncoder 用於定義Encoder
target String System.out 定義輸出目標,可選值System.outSystem.err
withJansi boolean false 是否支援Jansi,這是一個支援多彩ANSI編碼的類庫,用於輸出彩色控制檯字型

ConsoleAppender的使用例子如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
    <import class="ch.qos.logback.core.ConsoleAppender"/>

    <appender name="STDOUT" class="ConsoleAppender">
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

RollingFileAppender

RollingFileAppenderFileAppender的子類,支援輸出日誌到檔案中,並且支援通過滾動規則(RollingPolicy)的設定,可以安裝內建或者自定義規則去分割、歸檔日誌檔案。RollingFileAppender支援的引數如下:

引數 型別 預設值 描述
file String - 用於定義當前日誌輸出的目標檔案
append boolean true 用於定義當前日誌輸出是否追加模式
rollingPolicy ch.qos.logback.core.rolling.RollingPolicy - 日誌檔案滾動策略
triggeringPolicy ch.qos.logback.core.rolling.TriggeringPolicy - 日誌檔案滾動時機觸發策略
prudent boolean false 是否支援prudent模式(開啟此模式會在FileLock保護下寫入日誌檔案),FileAppender支援此模式

常用的RollingPolicy內建實現有:

  • TimeBasedRollingPolicy:最常用的日誌滾動策略,基於日期時間進行滾動分割和歸檔
引數 型別 預設值 描述
fileNamePattern String - 檔名格式,例如/var/log/app/server.%d{yyyy-MM-dd, UTC}.log.gz
maxHistory int - 最大歸檔檔案數量
totalSizeCap FileSize - 所有歸檔檔案總大小的上限
cleanHistoryOnStart boolean false 標記為trueAppender啟動時候清理(不合法的)歸檔日誌檔案
  • SizeAndTimeBasedRollingPolicy:基於日誌檔案大小或者日期時間進行滾動分割和歸檔
引數 型別 預設值 描述
fileNamePattern String - 檔名格式,例如/var/log/app/server.%d{yyyy-MM-dd, UTC}.%i.log.gz
maxHistory int - 最大歸檔檔案數量
totalSizeCap FileSize - 所有歸檔檔案總大小的上限
cleanHistoryOnStart boolean false 標記為trueAppender啟動時候清理(不合法的)歸檔日誌檔案
  • FixedWindowRollingPolicy:基於日誌檔案大小或者日期時間進行滾動分割和歸檔
引數 型別 預設值 描述
fileNamePattern String - 檔名格式,例如/var/log/app/server.%d{yyyy-MM-dd, UTC}.log.gz
minIndex int - 視窗索引下界
maxIndex int - 視窗索引上界

常用的TriggeringPolicy內建實現有:

  • SizeBasedTriggeringPolicy:基於檔案大小的觸發策略
  • DefaultTimeBasedFileNamingAndTriggeringPolicylogback內部使用):基於日期時間和檔名通過判斷系統日期時間觸發

這裡值得注意的幾點:

  • TimeBasedRollingPolicy自身也實現了TriggeringPolicy介面(委託到DefaultTimeBasedFileNamingAndTriggeringPolicy中執行),提供了兜底的日誌檔案滾動時機觸發策略,所以在使用TimeBasedRollingPolicy的時候可以不需要指定具體的triggeringPolicy例項
  • SizeAndTimeBasedRollingPolicy使用了子元件SizeAndTimeBasedFNATP實現,舊版本一般使用SizeAndTimeBasedFNATP實現基於檔案大小或者日期時間進行日誌滾動歸檔功能,此元件在新版本中建議使用SizeAndTimeBasedRollingPolicy替代
  • logback會基於引數fileNamePattern中定義的檔名字尾去選擇對應的歸檔日誌檔案壓縮演算法,例如.zip會選用ZIP壓縮演算法,.gz會選用GZIP壓縮演算法
  • SizeAndTimeBasedRollingPolicyFixedWindowRollingPolicyfileNamePattern引數都支援%i佔位符,用於定義歸檔檔案的索引值,其實索引為0
  • FixedWindowRollingPolicySizeBasedTriggeringPolicy組合使用可以實現基於檔案大小進行日誌滾動的功能(TimeBasedRollingPolicy的對標功能)

AsyncAppender

AsyncAppender用於非同步記錄日誌,需要搭配其他型別的Appender使用,直觀上看就是把"非同步"功能賦予其他Appender例項。AsyncAppender支援的引數如下:

引數 型別 預設值 描述
queueSize int 256 存放日誌事件的阻塞佇列的最大容量
discardingThreshold int queueSize / 5 日誌事件丟棄閾值,阻塞佇列剩餘容量小於此閾值,會丟棄除了WARNERROR級別的其他所有級別的日誌事件,此閾值設定為0相當於不會丟棄任意日誌事件
includeCallerData boolean false 日誌事件中是否包含呼叫者資料,設定為true會新增呼叫執行緒資訊、MDC中的資料等
maxFlushTime int 1000 非同步日誌寫入工作執行緒退出的最大等待時間,單位為毫秒
neverBlock boolean false 是否永不阻塞(當前應用的呼叫執行緒),設定為true的時候佇列滿了會直接丟棄當前新新增的日誌事件

需要通過<appender-ref>標籤關聯一個已經存在的Appender例項到一個全新的AsyncAppender例項中,並且一個AsyncAppender例項是可以基於多個<appender-ref>標籤新增多個Appender例項,例如:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
    <import class="ch.qos.logback.core.ConsoleAppender"/>
    <import class="ch.qos.logback.classic.AsyncAppender"/>

    <appender name="STDOUT" class="ConsoleAppender">
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC_STDOUT" class="AsyncAppender">
        <queueSize>1024</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="STDOUT"/>
        <!-- <appender-ref ref="OTHER_APPENDER"/> -->
    </appender>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="ASYNC_STDOUT"/>
    </root>
</configuration>

指定配置檔案進行初始化

logback內建的初始化策略(按照優先順序順序)如下:

  • 通過ClassPath中的logback-test.xml檔案初始化
  • 通過ClassPath中的logback.xml檔案初始化
  • 通過SPI的方式由ClassPath中的META-INF\services\ch.qos.logback.classic.spi.Configurator進行初始化
  • 如果前面三步都沒有配置,則通過BasicConfigurator初始化,提供最基礎的日誌處理功能

可以通過命令列引數logback.configurationFile直接指定外部的logback配置檔案(字尾必須為.xml或者.groovy),這種初始化方式會忽略內建的初始化策略,例如:

java -Dlogback.configurationFile=/path/conf/config.xml app.jar

或者設定系統引數(下面的Demo來自官方例子):

public class ServerMain {
    public static void main(String args[]) throws IOException, InterruptedException {
       // must be set before the first call to LoggerFactory.getLogger();
       // ContextInitializer.CONFIG_FILE_PROPERTY is set to "logback.configurationFile"
       System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, "/path/to/config.xml");
       ...
    }   
}

這種方式要求儘量不能存在靜態成員變數呼叫了LoggerFactory.getLogger()方法,因為有可能會導致提前使用內建的初始化策略進行初始化。

程式設計式初始化

為了完全控制logback的初始化,可以使用純程式設計式進行設定(下面的程式設計式配置按照"最佳實踐"中的配置檔案進行編寫):

import ch.qos.logback.classic.AsyncAppender;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.filter.ThresholdFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import org.slf4j.LoggerFactory;

/**
 * @author throwable
 * @version v1
 * @description
 * @since 2022/2/13 13:09
 */
public class LogbackLauncher {

    public static void main(String[] args) throws Exception {
        LoggerContext loggerContext = (LoggerContext) org.slf4j.LoggerFactory.getILoggerFactory();
        loggerContext.reset();
        Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
        // 移除所有Appender
        rootLogger.detachAndStopAllAppenders();
        // RollingFileAppender
        PatternLayoutEncoder fileEncoder = new PatternLayoutEncoder();
        fileEncoder.setContext(loggerContext);
        fileEncoder.setPattern("[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] ${app} - %msg%n");
        fileEncoder.start();
        RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<>();
        fileAppender.setContext(loggerContext);
        fileAppender.setName("FILE");
        fileAppender.setFile("/data/log-center/api-gateway/server.log");
        fileAppender.setAppend(true);
        fileAppender.setEncoder(fileEncoder);
        ThresholdFilter fileFilter = new ThresholdFilter();
        fileFilter.setLevel("INFO");
        fileAppender.addFilter(fileFilter);
        TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new TimeBasedRollingPolicy<>();
        rollingPolicy.setParent(fileAppender);
        rollingPolicy.setContext(loggerContext);
        rollingPolicy.setFileNamePattern("/data/log-center/api-gateway/server.%d{yyyy-MM-dd}.log.gz");
        rollingPolicy.setMaxHistory(14);
        rollingPolicy.start();
        fileAppender.setRollingPolicy(rollingPolicy);
        fileAppender.start();
        AsyncAppender asyncAppender = new AsyncAppender();
        asyncAppender.setName("ASYNC_FILE");
        asyncAppender.setContext(loggerContext);
        asyncAppender.setDiscardingThreshold(0);
        asyncAppender.setQueueSize(1024);
        asyncAppender.addAppender(fileAppender);
        asyncAppender.start();
        // ConsoleAppender
        PatternLayoutEncoder consoleEncoder = new PatternLayoutEncoder();
        consoleEncoder.setContext(loggerContext);
        consoleEncoder.setPattern("[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n");
        consoleEncoder.start();
        ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
        consoleAppender.setContext(loggerContext);
        consoleAppender.setEncoder(consoleEncoder);
        ThresholdFilter consoleFilter = new ThresholdFilter();
        consoleFilter.setLevel("DEBUG");
        consoleAppender.addFilter(consoleFilter);
        consoleAppender.start();
        rootLogger.setLevel(Level.DEBUG);
        rootLogger.setAdditive(false);
        rootLogger.addAppender(consoleAppender);
        rootLogger.addAppender(asyncAppender);

        org.slf4j.Logger logger = LoggerFactory.getLogger(LogbackDemo1.class);
        logger.debug("debug nano => {}", System.nanoTime());
        logger.info("info nano => {}", System.nanoTime());
        logger.warn("warn nano => {}", System.nanoTime());
        logger.error("error nano => {}", System.nanoTime());
    }
}

最佳實踐

實踐中建議使用logback文件中提到的最常用的:RollingFileAppender + TimeBasedRollingPolicy + ConsoleAppender(這個是為了方便本地開發除錯)組合。一般來說,日誌檔案最終會通過Filebeat等日誌收集元件上傳到ELK體系,在合理定義日誌的輸出格式(例如在輸出格式中指定Level引數)前提下,其實可以不拆分不同級別的日誌檔案並且輸出所有INFO或者以上級別的日誌,最終在Kibana中也可以輕易通過引數level: ${LEVEL}進行不同級別的日誌查詢。而對於效能要求比較高的服務例如API閘道器,建議把RollingFileAppender關聯到AsyncAppender例項中,在記憶體足夠的前提下調大queueSize引數並且設定discardingThreshold = 0(佇列滿了不丟棄日誌事件,有可能會阻塞呼叫執行緒,無法忍受可以自行擴充套件非同步日誌功能)。在伺服器磁碟充足的前提下,一般對於歸檔日誌的檔案大小不設定上限,只設置最大歸檔檔案數量,建議數量為14 ~ 30(也就是2周到1個月之間)。下面是一個模板:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <property name="app" value="應用名,例如api-gateway"/>
    <property name="filename" value="檔名字首,例如server"/>

    <import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
    <import class="ch.qos.logback.core.rolling.RollingFileAppender"/>
    <import class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"/>
    <import class="ch.qos.logback.core.ConsoleAppender"/>
    <import class="ch.qos.logback.classic.AsyncAppender"/>
    <import class="ch.qos.logback.classic.filter.ThresholdFilter"/>

    <appender name="FILE" class="RollingFileAppender">
        <file>/data/log-center/${app}/${filename}.log</file>
        <rollingPolicy class="TimeBasedRollingPolicy">
            <fileNamePattern>/data/log-center/${app}/${filename}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>14</maxHistory>
        </rollingPolicy>
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] ${app} - %msg%n</pattern>
        </encoder>
        <filter class="ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <appender name="STDOUT" class="ConsoleAppender">
        <encoder class="PatternLayoutEncoder">
            <pattern>[%date{ISO8601}] [%level] %logger{80} [%thread] [%X{TRACE_ID}] - %msg%n</pattern>
        </encoder>
        <filter class="ThresholdFilter">
            <level>DEBUG</level>
        </filter>
    </appender>

    <appender name="ASYNC_FILE" class="AsyncAppender">
        <queueSize>1024</queueSize>
        <!-- 佇列滿了不丟棄任一日誌事件 -->
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="FILE"/>
    </appender>

    <!-- 需要覆蓋日誌級別,減少不關注的日誌輸出 -->
    <logger name="sun.rmi" level="error"/>
    <logger name="sun.net" level="error"/>
    <logger name="javax.management" level="error"/>
    <logger name="org.redisson" level="warn"/>
    <logger name="com.zaxxer" level="warn"/>

    <root level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC_FILE"/>
    </root>
</configuration>

小結

這篇文章僅僅介紹logback最新版本的一些基本配置和實踐經驗,也作為一篇日後隨時可以拿起使用的流水賬筆記存檔。

參考資料:

(本文完 c-2-d e-a-20220212 這一兩個月的基金有點可怕)