1. 程式人生 > >關於非同步log4j2中location資訊列印問題

關於非同步log4j2中location資訊列印問題

背景:專案改造過程中將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 官方文件