因近期需要編寫J2EE程序,所以簡單學習了Log4j2,這里把我學習的一些信息做記錄:
1、從HelloWorld開始
參考:http://logging.apache.org/log4j/2.x/manual/api.html
首先創建一個Java Project,如下圖,在項目中創建lib文件夾,將log4j的api和core包復制進去並配置到項目編譯路徑中。
創建包com.demo並在包內創建類HelloWorld。
HelloWorld類的內容如下:
package com.demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class HelloWorld {
private static final Logger logger = LogManager.getLogger("HelloWorld");
public static void main(String[] args) {
String hello = "Hello, World!";
logger.trace("TRACE: " + hello);
logger.debug("DEBUG: " + hello);
logger.info("INFO: " + hello);
logger.warn("WARN: " + hello);
logger.error("ERROR: " + hello);
logger.fatal("FATAL: " + hello);
}
}
運行HelloWorld,結果顯示如下:
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
00:06:16.530 [main] ERROR HelloWorld - ERROR: Hello, World!
00:06:16.532 [main] FATAL HelloWorld - FATAL: Hello, World!
運行時提示沒有找到Log4j2的配置文件,使用默認配置,只顯示error到控制台。
缺省的配置等同於如下配置,其中Root指定的level是error,所有只輸出了error和fatal級別的日志。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
2、理解log4j2的結構
參考:http://logging.apache.org/log4j/2.x/manual/architecture.html
結合我們的HelloWorld程序,我們看一下log4j2的結構:
LoggerContext是整個Log系統的錨點,每一個LoggerContext會含有一個Configuration,在congfiguration中會包含Appender(輸出器)、Filter(過濾器)、LoggerConfig及StrSubstitutor的引用。
當我們在配置文件中聲明一個Loggers時就會創建一個LoggerConfig, LoggerConfig包含有一組Filter,同時持有一組Appender的引用。LoggerConfig所收到的所有LogEvent首先經過過濾器處理才會傳遞給Appendar輸出。
Filter會存在三種返回結果:Accept、Deny、Neutral。Accept表示事件將直接被處理並不繼續轉發其他Filter,Deny表示事件將被忽略,Neutral表示事件將被轉發給下一個filter,如果沒有后續的filter,事件將被處理。
3、理解Named Hierarchy (日志名稱層次規則)
首先我們在com.demo包內新增一個類NamedHierarchy:
package com.demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NamedHierarchy {
private static final Logger logger = LogManager.getLogger(NamedHierarchy.class);
public static void main(String[] args) {
// TODO Auto-generated method stub
String nh = "Named Hierarchy";
logger.getLevel();
logger.trace("TRACE: " + nh + " " + logger.getLevel());
NamedHierarchy n = new NamedHierarchy();
n.run();
logger.error("ERROR: " + nh + " " + logger.getLevel());
}
public void run(){
String nh = "NamedHierarchy.run";
logger.debug("DEBUG: " + nh + " " + logger.getLevel());
}
}
在src下新增log4j2.xml,並按如下修改文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.demo.NamedHierarchy" level="trace">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="com.demo" level="debug">
<AppenderRef ref="Console"/>
</Logger>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
工程結構如下:
運行NamedHierarchy你會發現結果如下:
01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE
01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE
01:33:48.864 [main] TRACE com.demo.NamedHierarchy - TRACE: Named Hierarchy TRACE
01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE
01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE
01:33:48.867 [main] DEBUG com.demo.NamedHierarchy - DEBUG: NamedHierarchy.run TRACE
01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE
01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE
01:33:48.868 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy TRACE
為什么同樣的日志信息會被輸出三次呢?這是因為logger的命名符合命名層次規則,而層次關系是由對應的LoggerConfig來維護的。root是整個層次規則(或結構)的頂層,父節點和子節點是通過“.”來識別的,如com.demo是com.demo.NamedHierarchy的父節點,com.demo.NamedHierarchy是com.demo的子節點。
同時Logger的命名和類的命名又有關聯的,如果我們在配置文件中配置一個Logger的名稱為com.demo.NamedHierarchy,那么類com.demo.NamedHierarchy中的Logger就會匹配到這一配置,同時所有父節點的配置也會被適用。所以在我們使用logger.trace("TRACE: " + nh + " " + logger.getLevel()); 輸出日志時,配置文件中3個Logger對應的Appender分別被調用。
如果你把
<Logger name="com.demo.NamedHierarchy" level="trace">
修改為
<Logger name="com.demo.NamedHierarchy" level="error">
運行,結果如下:
21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR
21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR
21:40:44.389 [main] ERROR com.demo.NamedHierarchy - ERROR: Named Hierarchy ERROR
為什么父節點的Appender沒有輸出?這是由於LogEvent的level和LoggerConfig的level在特定組合下,LogEvent不會被繼續向下轉發處理,組合關系如下,其中YES表示轉發繼續處理,NO表示不繼續轉發。
Event Level |
LoggerConfig Level |
||||||
聽 |
TRACE |
DEBUG |
INFO |
WARN |
ERROR |
FATAL |
OFF |
ALL |
YES |
YES |
YES |
YES |
YES |
YES |
NO |
TRACE |
YES |
NO |
NO |
NO |
NO |
NO |
NO |
DEBUG |
YES |
YES |
NO |
NO |
NO |
NO |
NO |
INFO |
YES |
YES |
YES |
NO |
NO |
NO |
NO |
WARN |
YES |
YES |
YES |
YES |
NO |
NO |
NO |
ERROR |
YES |
YES |
YES |
YES |
YES |
NO |
NO |
FATAL |
YES |
YES |
YES |
YES |
YES |
YES |
NO |
OFF |
NO |
NO |
NO |
NO |
NO |
NO |
NO |
如果你不希望LogEvent被按命名層次分別處理,只希望最低一層的子節點處理,那么可以在Logger配置時增加additivity="false",如:
<Logger name="com.demo.NamedHierarchy" level="trace" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
4、定時重新加載配置
Log4j2支持定時檢查配置文件是否變化並根據變化重新加載,這個功能在實際應用中比較有價值,比如產品上網后有問題,如果默認的error級別的日志不能支撐定位,需要切換到trace級別,定時加載的功能就可以避免重啟服務,畢竟商用產品重啟服務代價還是很大的,有時候還必須先獲取客戶的授權。
在Configuration中增加monitorInterval="30"參數,其中30指30秒,如下:
<Configuration monitorInterval="30">
...
</Configuration>
5、常用的Appender
關於詳細的Appender及配置參數,建議查看API:http://logging.apache.org/log4j/2.x/manual/appenders.html
5.1 FileAppender
FileAppender支持把日志信息寫入文件,典型的配置如下:
append用來設置程序開始時日志是否被追加到原日志文件上,fileName表示要保存的文件名稱,bufferedIO和bufferSize表示將日志內容緩存到bufferSize大小后寫入文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="MyFile" append="true" fileName="logs/mylog.log" bufferedIO="true" bufferSize="512">
<PatternLayout>
<Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
5.2 RollingFileAppender
循環寫入文件,典型配置如下:
以下的配置可以簡單概括為:初始日志名稱是rolling.log,當rolling.log日志文件達到1KB時,將rolling.log修改為app-日期-1.log並壓縮為app-日期-1.log.gz,rolling.log重新開始寫;當再次達到1KB時,將rolling.log修改為app-日期-2.log並壓縮為app-日期-2.log.gz,rolling.log重新開始寫;當再次達到1KB時,刪除app-日期-1.log.gz,修改app-日期-2.log.gz為app-日期-1.log.gz,將rolling.log修改為app-日期-2.log並壓縮為app-日期-2.log.gz,rolling.log重新開始寫;
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<RollingFile name="RollingFile" fileName="logs/rolling.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="1 KB"/>
</Policies>
<DefaultRolloverStrategy fileIndex="max" max="2"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
建議你使用此配置寫一個簡單的腳步驗證效果。
更多詳細內容,請查看官方文檔:http://logging.apache.org/log4j/2.x/manual/architecture.html
http://blog.csdn.net/axwolfer/article/details/40718609