關於非同步log4j2中location資訊列印問題
阿新 • • 發佈:2018-11-07
背景:專案改造過程中將log4j2改成非同步,發現行號沒有列印,於是扒了下官方文件,大概陳述下:
先說一下這個問題是怎麼解決的,然後稍微擴充套件一下其他配置,有興趣的可以往下看或者溜一遍官方文件
- 解決:在
<AsyncLogger>
標籤中配置includeLocation="true"
, - 擴充套件:
1、additivity:這個屬性的意思是需不需要列印此logger繼承的父logger,如果是false則只打印當前logger;如果是true則繼續列印上一層的logger,直到root。
2、實現error日誌列印雙份:info.log中列印一份(即info中包括info和error日誌),error.log中列印一份(只包括error日誌),這樣的好處是能根據error日誌出現的上下文快速定位到程式bug出現的位置,這個功能需要使用過濾器實現,比如:
<RollingFile name="error" fileName="${log_home}/error.log" immediateFlush="false" append="true" filePattern="/history/error-%d{yyyy-MM-dd}.log.gz"> <Filters> <!--只允許級別為error的日誌通過--> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> </Filters> <PatternLayout charset="UTF-8"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} #| %p #| %t #| %c{-1}:%L #| %m%n</Pattern> </PatternLayout> <Policies> <!--預設列印週期為一天--> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> <!--儲存日誌個數為15個--> <DefaultRolloverStrategy max="15"/> </RollingFile>
log4j2的非同步形式大概分為兩種:全非同步和同步非同步混合。
1、全非同步
- 實現方式:官方給出了兩種實現形式:第一種將系統屬性log4j2.contextSelector設定 為org.apache.logging.log4j.core.async.AsyncLoggerContextSelector,即
System.setProperty("log4j2.contextSelector, "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
官方給出了一個不需要location資訊的配置檔案示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Don't forget to set system property
-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
to make all loggers asynchronous. -->
<Configuration status="WARN">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RandomAccessFile name="RandomAccessFile" fileName="async.log" immediateFlush="false" append="false">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<!--不需要列印location資訊-->
<Root level="info" includeLocation="false">
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
同步非同步混合
相比起全非同步,混合非同步可能會花費更多的效能,
官方給出了一個混合非同步的配置例子:
<?xml version="1.0" encoding="UTF-8"?>
<!-- No need to set system property "log4j2.contextSelector" to any value
when using <asyncLogger> or <asyncRoot>. -->
<Configuration status="WARN">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"
immediateFlush="false" append="false">
<PatternLayout>
<Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<!-- pattern layout actually uses location, so we need to include it -->
<AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
<AppenderRef ref="RandomAccessFile"/>
</AsyncLogger>
<Root level="info" includeLocation="true">
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
對於location資訊:
預設情況下,非同步日誌記錄器不會將location資訊傳遞給I/O執行緒,如果你的layouts或custom過濾器需要location資訊,你需要在所有相關日誌記錄器(包括根日誌記錄器)的配置中設定“includeLocation=true”
如果其中一個layouts配置了關於位置的資訊,比如HTML locationInfo,或者表示式%C或$class、%F或%file、%l或%location、%L或%line、%M或%method,log4j將會獲取堆疊的快照(snapshot),並遍歷堆疊跟蹤以查詢位置資訊,因此會消耗較多的時間。
這是一個昂貴的操作:比同步logger慢1.3到5倍,同步日誌記錄器在獲取堆疊快照之前會等待儘可能長的時間,如果不需要位置,那麼快照將永遠不會被捕獲。
瞭解更多請訪問官方文件:Apache Log4j2 Async 官方文件