對於一個應用程序來說日志記錄是必不可少的一部分。線上問題追蹤,基於日志的業務邏輯統計分析等都離不日志。java領域存在多種日志框架,目前常用的日志框架包括Log4j,Log4j 2,Commons Logging,Slf4j,Logback,Jul。
Log4j Apache Log4j是一個基於Java的日志記錄工具。它是由Ceki Gülcü首創的,現在則是Apache軟件基金會的一個項目。 Log4j是幾種Java日志框架之一。
Log4j 2 Apache Log4j 2是apache開發的一款Log4j的升級產品。
Commons Logging Apache基金會所屬的項目,是一套Java日志接口,之前叫Jakarta Commons Logging,後更名為Commons Logging。
Slf4j 類似於Commons Logging,是一套簡易Java日志門面,本身並無日志的實現。(Simple Logging Facade for Java,縮寫Slf4j)。
Logback 一套日志組件的實現(slf4j陣營)。
Jul (Java Util Logging),自Java1.4以來的官方日志實現。
看了上面的介紹是否會覺得比較混亂,這些日志框架之間有什麼異同,都是由誰在維護? 下文會逐一介紹。
1996年早期,歐洲安全電子市場項目組決定編寫它自己的程序跟蹤API(Tracing API)。經過不斷的完善,這個API終於成為一個十分受歡迎的Java日志軟件包,即Log4j。後來Log4j成為Apache基金會項目中的一員。
期間Log4j近乎成了Java社區的日志標准。據說Apache基金會還曾經建議sun引入Log4j到java的標准庫中,但Sun拒絕了。
2002年Java1.4發布,Sun推出了自己的日志庫JUL(Java Util Logging),其實現基本模仿了Log4j的實現。在JUL出來以前,log4j就已經成為一項成熟的技術,使得log4j在選擇上占據了一定的優勢。
接著,Apache推出了Jakarta Commons Logging,JCL只是定義了一套日志接口(其內部也提供一個Simple Log的簡單實現),支持運行時動態加載日志組件的實現,也就是說,在你應用代碼裡,只需調用Commons Logging的接口,底層實現可以是log4j,也可以是Java Util Logging。
後來(2006年),Ceki Gülcü不適應Apache的工作方式,離開了Apache。然後先後創建了slf4j(日志門面接口,類似於Commons Logging)和Logback(Slf4j的實現)兩個項目,並回瑞典創建了QOS公司,QOS官網上是這樣描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一個通用,可靠,快速且靈活的日志框架)。
現今,Java日志領域被劃分為兩大陣營:Commons Logging陣營和SLF4J陣營。
Commons Logging在Apache大樹的籠罩下,有很大的用戶基數。但有證據表明,形式正在發生變化。2013年底有人分析了GitHub上30000個項目,統計出了最流行的100個Libraries,可以看出slf4j的發展趨勢更好:
Log4j2與Log4j1發生了很大的變化,log4j2不兼容log4j1。
Commons Logging和Slf4j是日志門面(門面模式是軟件工程中常用的一種軟件設計模式,也被稱為正面模式、外觀模式。它為子系統中的一組接口提供一個統一的高層接口,使得子系統更容易使用)。log4j和Logback則是具體的日志實現方案。可以簡單的理解為接口與接口的實現,調用這只需要關注接口而無需關注具體的實現,做到解耦。
比較常用的組合使用方式是Slf4j與Logback組合使用,Commons Logging與Log4j組合使用。
Logback必須配合Slf4j使用。由於Logback和Slf4j是同一個作者,其兼容性不言而喻。
Commons logging是通過動態查找機制,在程序運行時,使用自己的ClassLoader尋找和載入本地具體的實現。詳細策略可以查看commons-logging-*.jar包中的org.apache.commons.logging.impl.LogFactoryImpl.java文件。由於OSGi不同的插件使用獨立的ClassLoader,OSGI的這種機制保證了插件互相獨立, 其機制限制了commons logging在OSGi中的正常使用。
Slf4j在編譯期間,靜態綁定本地的LOG庫,因此可以在OSGi中正常使用。它是通過查找類路徑下org.slf4j.impl.StaticLoggerBinder,然後綁定工作都在這類裡面進。
如果是在一個新的項目中建議使用Slf4j與Logback組合,這樣有如下的幾個優點。
Slf4j實現機制決定Slf4j限制較少,使用范圍更廣。由於Slf4j在編譯期間,靜態綁定本地的LOG庫使得通用性要比Commons logging要好。
Logback擁有更好的性能。Logback聲稱:某些關鍵操作,比如判定是否記錄一條日志語句的操作,其性能得到了顯著的提高。這個操作在Logback中需要3納秒,而在Log4J中則需要30納秒。LogBack創建記錄器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它獲取已存在的記錄器只需94納秒,而Log4J需要2234納秒,時間減少到了1/23。跟JUL相比的性能提高也是顯著的。
Commons Logging開銷更高 在使Commons Logging時為了減少構建日志信息的開銷,通常的做法是:
if(log.isDebugEnabled()){
log.debug("User name: " +
user.getName() + " buy goods id :" + good.getId());
}
在Slf4j陣營,你只需這麼做:
log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId());
也就是說,slf4j把構建日志的開銷放在了它確認需要顯示這條日志之後,減少內存和cup的開銷,使用占位符號,代碼也更為簡潔
Logback文檔免費。Logback的所有文檔是全面免費提供的,不象Log4J那樣只提供部分免費文檔而需要用戶去購買付費文檔。
具體的接入方式參見下圖
在實際環境中我們經常會遇到不同的組件使用的日志框架不同的情況,例如Spring Framework使用的是日志組件是Commons logging,XSocket依賴的則是Java Util Logging。當我們在同一項目中使用不同的組件時應該如果解決不同組件依賴的日志組件不一致的情況呢?現在我們需要統一日志方案,統一使用SLF4J,把他們的日志輸出重定向到SLF4J,然後 SLF4J 又會根據綁定器把日志交給具體的日志實現工具。Slf4j帶有幾個橋接模塊,可以重定向log4j,JCL和java.util.logging中的API到Slf4j。
遺留的api橋接方案
橋接方式參見下圖
使用slf4j橋接要注意事項
在使用slf4j橋接時要注意避免形成死循環,在項目依賴的jar包中不要存在以下情況。
slf4j官網
slf4j使用手冊1
slf4j使用手冊2
logback官網
commons logging官網