1. 程式人生 > >java 的日誌體系 分析 演化歷史 slf4j log4j logback

java 的日誌體系 分析 演化歷史 slf4j log4j logback

摘要: java的日誌系統繁雜,今天趁著解決日誌系統衝突的過程,順帶學習一下java的日誌系統並做個記錄 日誌演化歷史 最開始出現的是log4j,也是應用最廣泛的日誌系統,成為了目前java日誌系統事實上的標準,一切都是美好的 但java的開發主體sun公司認為自己才是正統,為了幹掉log4j在jdk1.4中增加了jul(因為在java.util.logging包下)日誌的實現,造成了目前開發者的混亂,迄今為止仍飽受詬病 各個日誌系統互相沒有關聯,替換和統一變的非常麻煩。

java的日誌系統繁雜,今天趁著解決日誌系統衝突的過程,順帶學習一下java的日誌系統並做個記錄

日誌演化歷史

  • 最開始出現的是log4j,也是應用最廣泛的日誌系統,成為了目前java日誌系統事實上的標準,一切都是美好的
  • 但java的開發主體sun公司認為自己才是正統,為了幹掉log4j在jdk1.4中增加了jul(因為在java.util.logging包下)日誌的實現,造成了目前開發者的混亂,迄今為止仍飽受詬病
  • 各個日誌系統互相沒有關聯,替換和統一變的非常麻煩。A專案用log4j作為日誌系統,但同時引了B專案,而B專案用jul作為日誌系統,那麼你的應用就得使用兩個日誌系統
  • 為了搞定這個坑爹的問題,開源社群apache提供了一個日誌框架作為日誌的抽象,叫commons-logging
    ,也被稱為jcl(java common logging),jcl對各種日誌介面進行抽象,抽象出一個介面層,對每個日誌實現都適配或者轉接,這樣這些提供給別人的庫都直接使用抽象層即可,較好的解決了上述問題
  • 但這時,作為元老級日誌log4j的作者覺得jcl不夠好,再度出山,搞出了一個更加牛逼的新的日誌框架slf4j(這個也是抽象層),同時針對slf4j的介面實現了一套日誌系統,即傳說中的logback
  • 同時這個作者心情一好,又把log4j進行了改造,就是所謂的log4j2,同時支援jcl以及slf4j

JCL

使用JCL一般(如果是log4j可以不需要)需要一個配置commons-logging.properties在classpath上,這個檔案有一行程式碼:

org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl

用於通知JCL想要使用哪個日誌系統。使用者只要修改LogFactory的實現,就能動態的切換日誌系統

SLF4J

slf4j的設計相對較為精巧,作者將介面以及實現分開,其中slf4j-api中定義了介面,開發者需要關心的就是這個介面,無需再關心下層如何實現,同時各個是slf4j介面的實現者只要遵循這個介面,就能夠做到日誌系統間的無縫相容

  • slf4j-api的實現目前比較出名的是介面開發者實現的logback,效能相較log4j來講更加優秀,也支援佔位符等新特性。
  • 同時為了相容log4j,slf4j-log4j12實現了slf4j-api,作為log4j相容的介面卡,使得使用者用起來像在用log4j
  • 為了相容jul,slf4j-jdk14也實現了slf4j-api,作為jul相容的介面卡,使得使用者用起來像在用jul
  • 有了實現,還需要一個橋接器,橋接器將對jcl的呼叫轉接到slf4j上:

    • jul-to-slf4j把對jul的呼叫橋接到slf4j上
    • jcl-over-slf4j把對jcl的呼叫橋接到slf4j上
    • log4j-over-slf4j把對log4j的呼叫橋接到slf4j上

日誌系統的衝突

多種日誌系統並不意味著程式中只能存在一種日誌系統,比如log4j與logback是完全可以共存的。
目前日誌系統的衝突主要分為兩種:

  • 同一個日誌系統的多個實現
  • 橋接介面與實現類

1) 同一個日誌系統的多個實現

像slf4j介面實現的衝突,如:

slf4j-log4j、logback、slf4j-jdk14、log4j2之間的衝突

這點很好理解,這幾個包都實現了slf4j的介面,同一介面只能有一個實現才能被jvm正確識別
但日誌系統仍然非常容易衝突,與傳統的jar衝突相同,當jvm發現兩個一模一樣的實現的時候,它就不知道選擇哪個或選擇了一個錯誤的,就會提示ClassNotFound.

2) 橋接jar與實現包
在日誌系統中,最常見的就是橋接jar包與實現包的衝突,如:

  • jul-to-slf4j 與 slf4j-jdk14
  • log4j-over-slf4j 與 slf4j-log4j
  • jcl-over-slf4j 與 jcl

因為轉接的實現就是將其餘的日誌系統呼叫進行一個轉發,既然要轉發,就必須要定義與原有物件相同的類名、包名,才能正確的被呼叫,所以橋接jar包就必然與實現包產生衝突。

各個日誌系統間的依賴關係

依賴關係可以見下圖:
日誌系統.png-13.5kB
其中

  • slf4j為純日誌介面
  • logback/slf4j-jdk14/slf4j-log4j12/log4j2均可認為是slf4j的實現類
  • jul/log4j作為最早開始的日誌系統,本身就是一種日誌的實現,沒有任何框架
  • jul-to-slf4j/log4j-to-slf4j/jcl-over-slf4j/作為橋接介面,可以將原有介面的內容進行接收,然後通過slf4j進行輸出

其餘常見問題

  • slf4j的幾個實現jar包一定會衝突,尤其要注意
  • slf4j-api和實現版本最好對應,尤其是1.6.x和1.5.x不相容,直接升級到最新版本
  • log4j與logback可以同時使用,logback實現slf4j的介面,與log4j沒有任何關係,完全可以同時使用
  • 建議選用slf4j + logback,或slf4j + log4j2
  • 日誌系統在正常情況下是不會影響應用效能的,但應該注意量,太大量的日誌會拖累效能

標籤(空格分隔): java


java的日誌系統繁雜,今天趁著解決日誌系統衝突的過程,順帶學習一下java的日誌系統並做個記錄

日誌演化歷史

  • 最開始出現的是log4j,也是應用最廣泛的日誌系統,成為了目前java日誌系統事實上的標準,一切都是美好的
  • 但java的開發主體sun公司認為自己才是正統,為了幹掉log4j在jdk1.4中增加了jul(因為在java.util.logging包下)日誌的實現,造成了目前開發者的混亂,迄今為止仍飽受詬病
  • 各個日誌系統互相沒有關聯,替換和統一變的非常麻煩。A專案用log4j作為日誌系統,但同時引了B專案,而B專案用jul作為日誌系統,那麼你的應用就得使用兩個日誌系統
  • 為了搞定這個坑爹的問題,開源社群apache提供了一個日誌框架作為日誌的抽象,叫commons-logging,也被稱為jcl(java common logging),jcl對各種日誌介面進行抽象,抽象出一個介面層,對每個日誌實現都適配或者轉接,這樣這些提供給別人的庫都直接使用抽象層即可,較好的解決了上述問題
  • 但這時,作為元老級日誌log4j的作者覺得jcl不夠好,再度出山,搞出了一個更加牛逼的新的日誌框架slf4j(這個也是抽象層),同時針對slf4j的介面實現了一套日誌系統,即傳說中的logback
  • 同時這個作者心情一好,又把log4j進行了改造,就是所謂的log4j2,同時支援jcl以及slf4j

JCL

使用JCL一般(如果是log4j可以不需要)需要一個配置commons-logging.properties在classpath上,這個檔案有一行程式碼:

org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl

用於通知JCL想要使用哪個日誌系統。使用者只要修改LogFactory的實現,就能動態的切換日誌系統

SLF4J

slf4j的設計相對較為精巧,作者將介面以及實現分開,其中slf4j-api中定義了介面,開發者需要關心的就是這個介面,無需再關心下層如何實現,同時各個是slf4j介面的實現者只要遵循這個介面,就能夠做到日誌系統間的無縫相容

  • slf4j-api的實現目前比較出名的是介面開發者實現的logback,效能相較log4j來講更加優秀,也支援佔位符等新特性。
  • 同時為了相容log4j,slf4j-log4j12實現了slf4j-api,作為log4j相容的介面卡,使得使用者用起來像在用log4j
  • 為了相容jul,slf4j-jdk14也實現了slf4j-api,作為jul相容的介面卡,使得使用者用起來像在用jul
  • 有了實現,還需要一個橋接器,橋接器將對jcl的呼叫轉接到slf4j上:

    • jul-to-slf4j把對jul的呼叫橋接到slf4j上
    • jcl-over-slf4j把對jcl的呼叫橋接到slf4j上
    • log4j-over-slf4j把對log4j的呼叫橋接到slf4j上

日誌系統的衝突

多種日誌系統並不意味著程式中只能存在一種日誌系統,比如log4j與logback是完全可以共存的。
目前日誌系統的衝突主要分為兩種:

  • 同一個日誌系統的多個實現
  • 橋接介面與實現類

1) 同一個日誌系統的多個實現

像slf4j介面實現的衝突,如:

slf4j-log4j、logback、slf4j-jdk14、log4j2之間的衝突

這點很好理解,這幾個包都實現了slf4j的介面,同一介面只能有一個實現才能被jvm正確識別
但日誌系統仍然非常容易衝突,與傳統的jar衝突相同,當jvm發現兩個一模一樣的實現的時候,它就不知道選擇哪個或選擇了一個錯誤的,就會提示ClassNotFound.

2) 橋接jar與實現包
在日誌系統中,最常見的就是橋接jar包與實現包的衝突,如:

  • jul-to-slf4j 與 slf4j-jdk14
  • log4j-over-slf4j 與 slf4j-log4j
  • jcl-over-slf4j 與 jcl

因為轉接的實現就是將其餘的日誌系統呼叫進行一個轉發,既然要轉發,就必須要定義與原有物件相同的類名、包名,才能正確的被呼叫,所以橋接jar包就必然與實現包產生衝突。

各個日誌系統間的依賴關係

依賴關係可以見下圖:
日誌系統.png-13.5kB
其中

  • slf4j為純日誌介面
  • logback/slf4j-jdk14/slf4j-log4j12/log4j2均可認為是slf4j的實現類
  • jul/log4j作為最早開始的日誌系統,本身就是一種日誌的實現,沒有任何框架
  • jul-to-slf4j/log4j-to-slf4j/jcl-over-slf4j/作為橋接介面,可以將原有介面的內容進行接收,然後通過slf4j進行輸出

其餘常見問題

  • slf4j的幾個實現jar包一定會衝突,尤其要注意
  • slf4j-api和實現版本最好對應,尤其是1.6.x和1.5.x不相容,直接升級到最新版本
  • log4j與logback可以同時使用,logback實現slf4j的介面,與log4j沒有任何關係,完全可以同時使用
  • 建議選用slf4j + logback,或slf4j + log4j2

  • 日誌系統在正常情況下是不會影響應用效能的,但應該注意量,太大量的日誌會拖累效能

   原文連結   https://yq.aliyun.com/articles/57769