一、log4j2概述
在日常的開發,測試和生產環境中,日志記錄了應用,服務運行過程中的關鍵信息,以及出現異常時的堆棧,這些信息常常作為查詢,定位,解決問題的關鍵,因此在任何系統中,對日志的使用得當,將極大的提高程序問題解決的效率。
Log4j的1.x版本雖然已經被廣泛使用於很多應用程序中,但由於出現內存泄漏等bug,代碼難以維護,以及需要使用老版本的jdk等劣勢,在2015年8月已經玩完。它的替代品,SLF4J,Logback,Log4j2對日志框架做了很多必要的改進。
SLF4J:SLF4J是眾多日志系統的內核,提供統一的接口,不提供具體實現,不是具體可使用可配置的日志系統。
Logback:提供了對SLF4J具體實現的日志系統,相比Log4j1.x,Logback的性能,使用場景,內存使用等方面的優化要遠遠強於Log4j1.x。
Log4j2:Log4j2雖然在各個方面都與logback非常相似,但是卻提供了更強的性能和並發性,下一代異步logger,易於拓展自定義需求的架構,是目前使用十分廣泛的日志框架。
二、log4j2配置節點說明
如下圖為log4j2的設計架構圖,接下里對設計圖中涉及的各節點做簡單的介紹
(1)LoggerContext:日志系統上下文
(2)Configuration:每一個 LoggerContext 都有一個有效的 Configuration, Configuration 包含所有的Appender 、Filter、LoggerConfig ,StrSubstitutor引用和對Layout的格式設置
(3)Logger : Logger繼承自 AbstractLogger,當配置被修改后,它將與不同的 LoggerConfig 相關聯,這導致其行為也被改變。
(4)LoggerConfig:LoggerConfig 對象在 Logger 被聲明時創建,它包含了一組用於處理事件的Appender引用,以及一組用於過濾傳遞給Appender事件的Filter,相當於是Appender的集合。
(5)Appender:Log4j2 還允許將記錄請求輸出到多個目標中,而這種輸出目標被稱為Appender。目前Appender的類型有控制台、文件、socket、Apache Flume、JMS、遠程UNIX 系統日志守護進程以及各種數據庫API,用戶可以根據需要選擇將日志輸出到不同的目標上,同時在一個Logger的配置中,允許開啟多個Appender。
(6)Filter :Log4j2 提供了Filter 來過濾消息事件,它可被應用於事件傳遞給LoggerConfig之前,及傳遞給LoggerConfig之后,即LoggerConfig的前后置攔截器。Filter包含了三種行為: Accept, Deny 或 Neutral,其中Accept,Deny分別代表着接受和拒絕,即過濾器接受或拒絕某種日志過濾表達式等,經過這兩種行為處理后將不再經過其他過濾器。Neutral代表着中立,意味着事件應由其他Filter來處理。如果未配置任何Filter,那么事件將直接被處理。
(7)Layout:Log4j2除了可以輸出到不同的目標Appender之外,還支持在目標中定義自定義的日志格式,Layout 負責對日志事件進行格式化,通過配置PatternLayout來實現。
(8)StrSubstitutor和StrLookup:這兩個組件用來對Log4j2中的各項配置進行動態變量賦值。
(9)日志級別:LoggerConfig會被分配一個日志級別,常用的級別包含TRACE, DEBUG, INFO, WARN, ERROR 和 FATAL
三、log4j2簡單默認配置
(1)對Log4j2配置的使用首先需要引入對應的core和api包,需要注意的是,如果項目中只引入了jar包而沒有對應的log4j2.xml配置文件,那么在eclipse中運行時則會打印如ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console的異常信息,並且輸出logger時可以看到只有error和fatal級別的被輸出來,是因為沒有配置文件就使用默認的,默認級別是error,所以只有error和fatal輸出來。
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.0</version> </dependency>
(2)配置簡單的log4j2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!-- 配置LoggerConfig,即Appenders的日志級別為WARN --> <Configuration status="WARN"> <!-- Appenders支持配置多個Appender,支持向不同的目標輸送日志,本例為配置向控制台輸出 --> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> </Console> </Appenders> <!-- Loggers支持配置多個Logger,可引用不同的目標Appender,也可根據業務需求定制特定要求的Appender --> <Loggers> <Root level="info"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
(3)加載配置文件的方式,Java代碼手動加載以及Web工程web.xml配置監聽及加載
<!-- Web工程方式加載 -->
<context-param> <param-name>log4jConfiguration</param-name> <param-value>classpath:log4j2.xml</param-value> </context-param> <listener> <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class> </listener>
/** * Java代碼手動加載配置文件 */ public class App { public static void main( String[] args ) { try{ File file = new File("src/main/resources/log4j2.xml"); BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); final ConfigurationSource source = new ConfigurationSource(in); Configurator.initialize(null, source); Logger logger = LogManager.getLogger(); logger.info("logger init and record..."); logger.error("error log level..."); logger.warn("warn log level..."); logger.info("info log level..."); logger.debug("debug log level..."); logger.trace("trace log level..."); }catch(Exception e){ e.printStackTrace(); } } }
(4)驗證結果,區分日志級別
上面第(3)步的代碼執行后打印的結果如下,可見打印了所有級別的日志,卻並沒有所有都輸出到控制台上是因為只會輸出比LoggerConfig定義較大的級別日志,級別排序:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL,由於配置文件中LoggerConfig定義的級別為WARN,所以正常只有WARN,ERROR和FATAL會打印,但驗證結果多了個INFO,是因為在Logger中引用了控制台的Appender,並單獨指定了級別為INFO。