今天要分享的內容是log4j的使用。
每個系統都有日誌記錄,而多數都是用的log4j,以爲會配置了,懂了,發現還是有些細節的問題,要問,說不上來
先來直接看配置吧和測試用例吧
jar包的依賴
<!-- log4j support -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j.properties文件如下,放在你的web的resource下面,推薦maven標準工程來
### 設置###
log4j.rootLogger = DEBUG,stdout,D,E
log4j.logger.A=DEBUG, stdout
log4j.logger.A.B=INFO, stdout
### 輸出信息到控制擡 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 輸出DEBUG 級別以上的日誌到=D://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 輸出ERROR 級別以上的日誌到=D://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
測試用例
import org.apache.log4j.Logger;
/**
* @author hankun
* @create 2017-06-06 18:32
*/
public class log4jTtest {
private static Logger logger = Logger.getLogger(log4jTtest.class);
private static Logger loggerA = Logger.getLogger("A");
private static Logger loggerA_B = Logger.getLogger("A.B");
/**
* @param args
*/
public static void main(String[] args) {
// 記錄debug級別的信息
logger.debug("This is debug message.");
// 記錄info級別的信息
logger.info("This is info message.");
// 記錄error級別的信息
logger.error("This is error message.");
loggerA_B.info("repeat three times in console");
loggerA.info("repeat two times in console");
logger.info("repeat one times in console");
}
}
注意上面的輸出結果,你知道輸出啥內容,則,就真正理解了
[DEBUG] 2017-06-06 19:05:03,477 method:log4jTtest.main(log4jTtest.java:18)
This is debug message.
[INFO ] 2017-06-06 19:05:03,479 method:log4jTtest.main(log4jTtest.java:20)
This is info message.
[ERROR] 2017-06-06 19:05:03,479 method:log4jTtest.main(log4jTtest.java:22)
This is error message.
[INFO ] 2017-06-06 19:05:03,479 method:log4jTtest.main(log4jTtest.java:24)
repeat three times in console
[INFO ] 2017-06-06 19:05:03,479 method:log4jTtest.main(log4jTtest.java:24)
repeat three times in console
[INFO ] 2017-06-06 19:05:03,479 method:log4jTtest.main(log4jTtest.java:24)
repeat three times in console
[INFO ] 2017-06-06 19:05:03,480 method:log4jTtest.main(log4jTtest.java:25)
repeat two times in console
[INFO ] 2017-06-06 19:05:03,480 method:log4jTtest.main(log4jTtest.java:25)
repeat two times in console
[INFO ] 2017-06-06 19:05:03,480 method:log4jTtest.main(log4jTtest.java:26)
repeat one times in console
問題如下
- 前面的三個輸出,不用解釋,都明白爲啥
- 爲啥那個loggerA_B,輸出了三次,而loggerA輸出了二次,logger輸出了一次?
log4j幾個重要的概念
- logger組件
- 簡單的說,它就是決定了應用程序中,哪些代碼哪些地方,有可能輸出日誌
- 這也就是爲什麼,每個類裏面上來,就是,logger的初始化,它決定了這個類有資格輸出日誌
- 首先Log4J中總是存在一個rootLogger,即使沒有顯示配置也是存在的,並且默認輸出級別爲DEBUG。
- Log4J中的層次是用’.’來分隔的,如log4j.logger.com.example.test,這裏並不是說log4j.logger後面一定是具體的包名乃至類名,
- appender組件
- 輸出地,也就是你的日誌想輸出到哪裏,把上面的logger裏面的日誌
- 再簡單點,就是輸出到控制檯和文件裏面,也就是上面的配置stdout和D和E
- 這個需要和下面的這個概念配合
- 輸出控制的概念
- Log4j默認把日誌信息分爲五個等級 all debug info warn error fatal off
- 只有大於設置的級別,纔會打印日誌,低於則忽略
- log4j.appender.threshold=ERROR,這種配置用於控制,一個appender的輸出級別
- 繼承的概念
- log4j.rootLogger=DEBUG, Console
- log4j.logger.A=DEBUG, Console
- log4j.logger.A.B=INFO, Console
- A.B繼承A,再繼承最頂級的root
- Log4j是根據Log的名字來判斷繼承關係的
來解釋一下,上面的輸出結果
- 首先是,debug,info和error前三個日誌輸出,它們的logger是log4jTtest.class初始化的,繼承根logger,因此就是debug級別,同時因爲還有D和E的兩個appender,所以你在d盤可以看到,有一個info的文件還有一個error的文件,這個日誌輸出沒問題
- 然後就是解釋那重複的三個,因爲loggerA_B,它是根據A.B這個參數初始化的,是有繼承的,滿足A.B的info級別的日誌輸出,必然滿足A的logger的日誌輸出,當然還有默認的根輸出,因此三次
- 而那個兩次的,它的logger是loggerA,繼承於根,因此,info的時候,它本身輸出一次,根也輸出一次,就是兩次了。
- 最後一個,用的是默認的根,當然,只能輸出一次了
問題來了,怎麼避免重複,因爲繼承父的logger?
log4j.additivity.A.B=false
logger A.B的日誌僅會輸出到自己Console中,不會繼承任何父logger的appender。
就加上面的這句,就解決了問題
總結
之前反反覆覆看了很多次,關於日誌log4j的配置,每次看完以爲會了,但是到了項目裏面,總是不知道,自己有時候打印的日誌到底跑哪裏去了,或者去哪裏看?
總結其原因就是,對於細節沒有掌握理解到位,比如就是這個logger的概念,如果你真正的明白了,就知道了
誰能產生日誌?logger
日誌放哪裏?appender
什麼級別的日誌纔會輸出?日誌級別
他們是相互獨立的組件,單獨配置,又是相互配合,一起使用的,n*m的這種概念
因此上面的配置文件,一個logger可以對應多個appender,而appender之間又是彼此獨立的。