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
- 但這時,作為元老級日誌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包就必然與實現包產生衝突。
各個日誌系統間的依賴關係
依賴關係可以見下圖:
其中
- 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包就必然與實現包產生衝突。
各個日誌系統間的依賴關係
依賴關係可以見下圖:
其中
- 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