前提
當前(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
有:
ConsoleAppender
FileAppender
RollingFileAppender
AsyncAppender
其中,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
佔位符,用於定義歸檔檔案的索引值,其實索引為0
FixedWindowRollingPolicy
和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 這一兩個月的基金有點可怕)