前提
當前(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.x和1.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用於接受指定日志級別集合的日志記錄,如果有更加精細的日志過濾條件(內置常用的LevelFilter、ThresholdFilter等無法滿足實際需求),可以自行實現ch.qos.logback.core.filter.Filter接口定制日志事件過濾策略。這份文件定義了五個appender,其中有2個用於異步增強,核心appender有3個:
STDOUT:ConsoleAppender,標准輸出同步日志打印,級別為DEBUG或以上ASYNC_INFO(INFO):RollingFileAppender,異步滾動文件追加日志打印,級別為INFO或者WARN,追加到文件/data/log-center/api-gateway/server.log,歸檔文件格式為/data/log-center/api-gateway/server-${yyyy-MM-dd}.log.${compression_suffix},歸檔文件最多保存14個副本ASYNC_ERROR(ERROR):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有:
ConsoleAppenderFileAppenderRollingFileAppenderAsyncAppender
其中,RollingFileAppender是FileAppender的擴展(子類),現實場景中ConsoleAppender和RollingFileAppender的適用范圍更廣。從類繼承關系上看,ConsoleAppender和FileAppender都支持定義Encoder,最常用的Encoder實現就是PatternLayoutEncoder,用於定制日志事件的最終輸出格式。關於Encoder,由於其參數格式太過靈活,參數眾多,限於篇幅本文不會展開介紹。
ConsoleAppender
ConsoleAppender用於追加日志到控制台,對於Java應用來說就是追加到System.out或者System.err。ConsoleAppender支持的參數如下:
| 參數 | 類型 | 默認值 | 描述 |
|---|---|---|---|
encoder |
ch.qos.logback.core.encoder.Encoder |
PatternLayoutEncoder |
用於定義Encoder |
target |
String |
System.out |
定義輸出目標,可選值System.out或System.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
RollingFileAppender是FileAppender的子類,支持輸出日志到文件中,並且支持通過滾動規則(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 |
標記為true則Appender啟動時候清理(不合法的)歸檔日志文件 |
SizeAndTimeBasedRollingPolicy:基於日志文件大小或者日期時間進行滾動分割和歸檔
| 參數 | 類型 | 默認值 | 描述 |
|---|---|---|---|
fileNamePattern |
String |
- |
文件名格式,例如/var/log/app/server.%d{yyyy-MM-dd, UTC}.%i.log.gz |
maxHistory |
int |
- |
最大歸檔文件數量 |
totalSizeCap |
FileSize |
- |
所有歸檔文件總大小的上限 |
cleanHistoryOnStart |
boolean |
false |
標記為true則Appender啟動時候清理(不合法的)歸檔日志文件 |
FixedWindowRollingPolicy:基於日志文件大小或者日期時間進行滾動分割和歸檔
| 參數 | 類型 | 默認值 | 描述 |
|---|---|---|---|
fileNamePattern |
String |
- |
文件名格式,例如/var/log/app/server.%d{yyyy-MM-dd, UTC}.log.gz |
minIndex |
int |
- |
窗口索引下界 |
maxIndex |
int |
- |
窗口索引上界 |
常用的TriggeringPolicy內置實現有:
SizeBasedTriggeringPolicy:基於文件大小的觸發策略DefaultTimeBasedFileNamingAndTriggeringPolicy(logback內部使用):基於日期時間和文件名通過判斷系統日期時間觸發
這里值得注意的幾點:
TimeBasedRollingPolicy自身也實現了TriggeringPolicy接口(委托到DefaultTimeBasedFileNamingAndTriggeringPolicy中執行),提供了兜底的日志文件滾動時機觸發策略,所以在使用TimeBasedRollingPolicy的時候可以不需要指定具體的triggeringPolicy實例SizeAndTimeBasedRollingPolicy使用了子組件SizeAndTimeBasedFNATP實現,舊版本一般使用SizeAndTimeBasedFNATP實現基於文件大小或者日期時間進行日志滾動歸檔功能,此組件在新版本中建議使用SizeAndTimeBasedRollingPolicy替代logback會基於參數fileNamePattern中定義的文件名后綴去選擇對應的歸檔日志文件壓縮算法,例如.zip會選用ZIP壓縮算法,.gz會選用GZIP壓縮算法SizeAndTimeBasedRollingPolicy和FixedWindowRollingPolicy的fileNamePattern參數都支持%i占位符,用於定義歸檔文件的索引值,其實索引為0FixedWindowRollingPolicy和SizeBasedTriggeringPolicy組合使用可以實現基於文件大小進行日志滾動的功能(TimeBasedRollingPolicy的對標功能)
AsyncAppender
AsyncAppender用於異步記錄日志,需要搭配其他類型的Appender使用,直觀上看就是把"異步"功能賦予其他Appender實例。AsyncAppender支持的參數如下:
| 參數 | 類型 | 默認值 | 描述 |
|---|---|---|---|
queueSize |
int |
256 |
存放日志事件的阻塞隊列的最大容量 |
discardingThreshold |
int |
queueSize / 5 |
日志事件丟棄閾值,阻塞隊列剩余容量小於此閾值,會丟棄除了WARN和ERROR級別的其他所有級別的日志事件,此閾值設置為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 這一兩個月的基金有點可怕)
