1. 程式人生 > >軍閥混戰之java常用日誌框架

軍閥混戰之java常用日誌框架

java常用日誌框架類別介紹

  • 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以來的官方日誌實現。

Java常用日誌框架歷史

  • 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的發展趨勢更好:

    pic1

  • Apache眼看有被Logback反超的勢頭,於2012-07重寫了log4j 1.x,成立了新的專案Log4j 2。Log4j 2具有logback的所有特性。

java常用日誌框架之間的關係

  • Log4j2與Log4j1發生了很大的變化,log4j2不相容log4j1。

  • Commons Logging和Slf4j是日誌門面(門面模式是軟體工程中常用的一種軟體設計模式,也被稱為正面模式、外觀模式。它為子系統中的一組介面提供一個統一的高層介面,使得子系統更容易使用)。log4j和Logback則是具體的日誌實現方案。可以簡單的理解為介面與介面的實現,呼叫這隻需要關注介面而無需關注具體的實現,做到解耦。

  • 比較常用的組合使用方式是Slf4j與Logback組合使用,Commons Logging與Log4j組合使用。

  • Logback必須配合Slf4j使用。由於Logback和Slf4j是同一個作者,其相容性不言而喻。

Commons Logging與Slf4j實現機制對比

Commons logging實現機制

Commons logging是通過動態查詢機制,在程式執行時,使用自己的ClassLoader尋找和載入本地具體的實現。詳細策略可以檢視commons-logging-*.jar包中的org.apache.commons.logging.impl.LogFactoryImpl.java檔案。由於OSGi不同的外掛使用獨立的ClassLoader,OSGI的這種機制保證了外掛互相獨立, 其機制限制了commons logging在OSGi中的正常使用。

Slf4j實現機制

Slf4j在編譯期間,靜態繫結本地的LOG庫,因此可以在OSGi中正常使用。它是通過查詢類路徑下org.slf4j.impl.StaticLoggerBinder,然後繫結工作都在這類裡面進。

如果在專案中如果選擇日誌框架

如果是在一個新的專案中建議使用Slf4j與Logback組合,這樣有如下的幾個優點。

  1. Slf4j實現機制決定Slf4j限制較少,使用範圍更廣。由於Slf4j在編譯期間,靜態繫結本地的LOG庫使得通用性要比Commons logging要好。

  2. Logback擁有更好的效能。Logback聲稱:某些關鍵操作,比如判定是否記錄一條日誌語句的操作,其效能得到了顯著的提高。這個操作在Logback中需要3納秒,而在Log4J中則需要30納秒。LogBack建立記錄器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它獲取已存在的記錄器只需94納秒,而Log4J需要2234納秒,時間減少到了1/23。跟JUL相比的效能提高也是顯著的。

  3. 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的開銷,使用佔位符號,程式碼也更為簡潔

  4. Logback文件免費。Logback的所有文件是全面免費提供的,不象Log4J那樣只提供部分免費文件而需要使用者去購買付費文件。

如何在專案中使用Slf4j

Slf4j與其他各種日誌元件的橋接

jar包名 說明
slf4j-log4j12-1.7.13.jar log4j1.2版本的橋接器,你需要將log4j.jar加入classpath。
slf4j-jdk14-1.7.13.jar java.util.logging的橋接器,JDK原生日誌框架。
slf4j-nop-1.7.13.jar NOP橋接器,默默丟棄一切日誌。
slf4j-simple-1.7.13.jar 一個簡單實現的橋接器,該實現輸出所有事件到System.err. 只有INFO以及高於該級別的訊息被列印,在小型應用中它也許是有用的。
slf4j-jcl-1.7.13.jar Jakarta Commons Logging 的橋接器. 這個橋接器將SLF4j所有日誌委派給JCL。
logback-classic-1.0.13.jar(requires logback-core-1.0.13.jar) slf4j的原生實現,logback直接實現了slf4j的介面,因此使用slf4j與 logback的結合使用也意味更小的記憶體與計算開銷

具體的接入方式參見下圖
pic2

如何橋接遺留的api

在實際環境中我們經常會遇到不同的元件使用的日誌框架不同的情況,例如Spring Framework使用的是日誌元件是Commons logging,XSocket依賴的則是Java Util Logging。當我們在同一專案中使用不同的元件時應該如果解決不同元件依賴的日誌元件不一致的情況呢?現在我們需要統一日誌方案,統一使用SLF4J,把他們的日誌輸出重定向到SLF4J,然後 SLF4J 又會根據繫結器把日誌交給具體的日誌實現工具。Slf4j帶有幾個橋接模組,可以重定向log4j,JCL和java.util.logging中的API到Slf4j。

遺留的api橋接方案

jar包名 作用
log4j-over-slf4j-version.jar 將log4j重定向到slf4j
jcl-over-slf4j-version.jar 將commos logging裡的Simple Logger重定向到slf4j
jul-to-slf4j-version.jar 將Java Util Logging重定向到slf4j

橋接方式參見下圖
pic3

使用slf4j橋接要注意事項

在使用slf4j橋接時要注意避免形成死迴圈,在專案依賴的jar包中不要存在以下情況。

多個日誌jar包形成死迴圈的條件 產生原因
log4j-over-slf4j.jar和slf4j-log4j12.jar同時存在 由於slf4j-log4j12.jar的存在會將所有日誌呼叫委託給log4j。但由於同時由於log4j-over-slf4j.jar的存在,會將所有對log4j api的呼叫委託給相應等值的slf4j,所以log4j-over-slf4j.jar和slf4j-log4j12.jar同時存在會形成死迴圈
jul-to-slf4j.jar和slf4j-jdk14.jar同時存在 由於slf4j-jdk14.jar的存在會將所有日誌呼叫委託給jdk的log。但由於同時jul-to-slf4j.jar的存在,會將所有對jul api的呼叫委託給相應等值的slf4j,所以jul-to-slf4j.jar和slf4j-jdk14.jar同時存在會形成死迴圈

-------------------------------------------------

關於log的日誌依賴配置(啟動報錯時,極低概率)

應用本身使用slf4j-api進行日誌輸出,可能需要根據自身情況進行配置日誌的依賴

    • 如果應用原本使用logback進行實際日誌輸出,請確認存在依賴log4j-over-slf4j,這個包提供了log4j的api,使專案中所有對log4j的依賴可以通過slf4j輸出日誌,並且確認沒有log4j和slf4j-log4j12,呼叫類似log4j -> slf4j -> logback -> log file

      <dependency>

          <groupId>org.slf4j</groupId>

          <artifactId>log4j-over-slf4j</artifactId>

      </dependency>

    • 如果應用原本使用log4j進行日誌輸出,您有可能需要引入slf4j-log4j12,這個包存在org.slf4j.impl.StaticLoggerBinder對log4j的實現,使得slf4j可以通過log4j輸出日誌,並且確認沒有log4j-over-slf4j

      <dependency>

          <groupId>org.slf4j</groupId>

          <artifactId>slf4j-log4j12</artifactId>

      </dependency>

      如果依賴了log4j-slf4j-impl,請刪除!!!

      <dependency>

          <groupId>org.apache.logging.log4j</groupId>

          <artifactId>log4j-slf4j-impl</artifactId>

      </dependency>

    • 如果應用原本使用log4j2進行日誌輸出,您有可能需要引入slf4j-ext,加入SGM後log4j2的載入有分支會執行到載入slf4j-ext中的org.slf4j.ext.EventData,如果不加入這個依賴有機率出現死鎖

      <dependency>

          <groupId>org.slf4j</groupId>

          <artifactId>slf4j-ext</artifactId>

          <version>1.7.25</version>

      </dependency>

      死鎖如下圖

 

 

1.log4j2

org.apache.logging.log4j.LogManager;

org.apache.logging.log4j.Logger;