Log4j2使用總結
Log4j 2 包含了基于LMAX 分離庫的下一代的異步日志系統,在多線程環境下,異步日志系統比 Log4j 1.x 和Logback 提高了10倍性能提升(吞吐量和延遲率 )。原文如下:
Log4j 2 contains next-generation Asynchronous Loggers based on the LMAX Disruptor library. In multi-threaded scenarios Asynchronous Loggers have 10 times higher throughput and orders of magnitude lower latency than Log4j 1.x and Logback.
Log4j2目前已經出到了beta8版本,估計beta9在最近一周將放出,試用了下,感覺還不錯,做如下總結!
我是從logback遷移到log4j2,
刪除掉原有的包 log4j-over-slf4j-1.6.4.jar logback-classic-1.0.7.jar logback-core-1.0.7.jar slf4j-api-1.6.4.jar
增添以下的包 log4j-over-slf4j-1.7.5.jar log4j-api-2.0-beta8.jar log4j-core-2.0-beta8.jar log4j-slf4j-impl-2.0-beta8.jar
由于作者推薦,為了性能考慮,盡量不要使用slf4j,但我依賴的第三方框架比如spring有對slf4j使用,所以對JAR包做了以上的取舍,所以原有代碼中要做如下的改動
改動前:import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(OOXX.class);
改動后:iimport org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
private static final Logger logger = LogManager.getLogger(OOXX.class);
配置文件log4j2.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- status=debug 可以查看log4j的裝配過程 --> <configuration status="off" monitorInterval="1800"> <properties> <property name="LOG_HOME">/log/fish</property> <!-- 日志備份目錄 --> <property name="BACKUP_HOME">{LOG_HOME}/backup</property> <property name="STAT_NAME">stat</property> <property name="SERVER_NAME">global</property> </properties> <appenders> <!-- 定義控制臺輸出 --> <Console name="Console" target="SYSTEM_OUT" follow="true"> <PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" /> </Console> <!-- 程序員調試日志 --> <RollingRandomAccessFile name="DevLog" fileName="${LOG_HOME}/${SERVER_NAME}" filePattern="${LOG_HOME}/${SERVER_NAME}.%d{yyyy-MM-dd-HH}.log"> <PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" /> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> </Policies> </RollingRandomAccessFile> <!-- 游戲產品數據分析日志 --> <RollingRandomAccessFile name="ProductLog" fileName="${LOG_HOME}/${SERVER_NAME}_${STAT_NAME}" filePattern="${LOG_HOME}/${SERVER_NAME}_${STAT_NAME}.%d{yyyy-MM-dd-HH}.log"> <PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" /> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> </Policies> </RollingRandomAccessFile> </appenders> <loggers> <!-- 3rdparty Loggers --> <logger name="org.springframework.core" level="info"> </logger> <logger name="org.springframework.beans" level="info"> </logger> <logger name="org.springframework.context" level="info"> </logger> <logger name="org.springframework.web" level="info"> </logger> <logger name="org.jboss.netty" level="warn"> </logger> <logger name="org.apache.http" level="warn"> </logger> <logger name="com.mchange.v2" level="warn"> </logger> <!-- Game Stat logger --> <logger name="com.u9.global.service.log" level="info" additivity="false"> <appender-ref ref="ProductLog" /> </logger> <!-- Root Logger --> <root level="DEBUG"> <appender-ref ref="DevLog" /> <appender-ref ref="Console" /> </root> </loggers> </configuration>
TimeBased Triggering Policy
基于時間的觸發策略。該策略主要是完成周期性的log文件封存工作。有兩個參數:
interval,integer型,指定兩次封存動作之間的時間間隔。單位:以日志的命名精度來確定單位,比如yyyy-MM-dd-HH 單位為小時,yyyy-MM-dd-HH-mm 單位為分鐘
modulate,boolean型,說明是否對封存時間進行調制。若modulate=true,則封存時間將以0點為邊界進行偏移計算。比如,modulate=true,interval=4hours,那么假設上次封存日志的時間為03:00,則下次封存日志的時間為04:00,之后的封存時間依次為08:00,12:00,16:00,。。。
存在問題:在Eclipse下一切運行正常,如果把應用打包成jar包發布后,cmd命令行模式下,即使Console開著的情況下,也沒法輸出,文件輸出也沒有任何日志。
問題已經解決,需要在MANIFEST.MF文件里Class-Path 最前加個'.',目的是讓與jar包平級的配置文件log4j2.xml加載進來。
比如
Class-Path: . lib/antlr-2.7.6.jar lib/other.jar
這樣,就把包含了log4j2.xml的路徑放到了classpath,因此,log4j2能讀取這個文件。感謝老外Jacob Kjome的回復!
log4j2 在Web的應用,把log4j2.xml放在src根目錄下,不需要任何在代碼級別的設置,直接類似JAVA應用一樣使用,但把servlet改成了servlet3.0,因為官網上描述如下:
The Short Story Log4j 2 "just works" in Servlet 3.0 and newer web applications. It is capable of automatically starting when the application deploys and shutting down when the application undeploys.Important Note! For performance reasons, containers often ignore certain JARs known not to contain TLDs or ServletContainerInitializers and do not scan them for web-fragments and initializers. Importantly, Tomcat 7 <7.0.43 ignores all JAR files named log4j*.jar, which prevents this feature from working. This has been fixed in Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 <7.0.43 you will need to change catalina.properties and remove "log4j*.jar" from the jarsToSkip property. You may need to do something similar on other containers if they skip scanning Log4j JAR files.
但發現在eclipse下servlet2.0 也可以用的,并且不用修改catalina.properties文件。我用的是apache-tomcat-7.0.42,很奇怪!
有時候,為了同一份log4j文件要支持寫到不同的log中(否則會導致打印的內容被覆蓋,其中一個進程寫不進log等問題),需要在載入的時候對內容進行動態修改,比如根據server id分別生成game1.log,game2.log
可以代碼進行加載log4文件
File file = new File("log4j2.xml"); BufferedInputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file));
final ConfigurationSource source = new ConfigurationSource(); source.setInputStream(in); Configurator.initialize(null, source); } catch (FileNotFoundException e) { e.printStackTrace(); }
要使用異步寫日志的功能,必須引入Disruptor
<asyncRoot> or <asyncLogger>
官方建議一般程序員查看的日志改成異步方式,一些運營日志改成同步
Asynchronous Appenders 和 Asynchronous Loggers 區別:
在</appenders> 節點里添加
<Async name="Async">
<AppenderRef ref="MyFile"/>
</Async>
為Asynchronous Appenders 性能比同步快,比Asynchronous Loggers慢
在loggers節點添加
<AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
<AppenderRef ref="RandomAccessFile"/>
</AsyncLogger>
或者添加
<!-- Root Logger -->
<asyncRoot level="DEBUG">
<appender-ref ref="DevLog" />
<appender-ref ref="Console" />
</asyncRoot>
為logger async 用的是無鎖并發技術,必須引入Disruptor
測試了下,單線程異步比同步效率提高了1倍。線程越多性能提高越明顯。
如果要加上位置信息比如哪個類,第幾行,需要設置 includeLocation="true" 但默認不設置好像也是true,
location 主要包含了如下:
If one of the layouts is configured with a location-related attribute like HTML locationInfo, or one of the patterns %C or $class, %F or %file, %l or %location, %L or %line, %M or %method, Log4j will take a snapshot of the stack, and walk the stack trace to find the location information.