天天看點

Java日志架構--從入門到放棄一、寫在前面二、曆史演進 三、實戰示範參考文檔

一、寫在前面

  • 随着曆史發展,Java語言湧現了不少優秀的日志架構,比如Log4j,Jul,Jcl,slf4j,logback等,它們之前存在了複雜的關系;
  • 關系複雜: 多個接口、不同實作、各種轉換器、複雜的橋接器;
  • 一個應用會依賴各種三方包,三方包各種依賴不同的日志元件,管理不善會導緻原有日志配置失效、應用啟動失敗;
  • 一般情況下偶爾會發生日志元件相關問題,會經常記不起來各種日志元件以及基本的依賴關系 、轉換關系等;
  • 一直想整理下Java日志架構,留作備用,終于到了要好好整理的時候,一切為了提高工作效率;
  • 最後也希望能幫助到大家了解日志架構、快速排查問題;

二、曆史演進

        要弄清楚Java日志架構,就不可避免的要講到日志架構的曆史發展,下面以時間先後的順序來一一介紹。

Java日志架構--從入門到放棄一、寫在前面二、曆史演進 三、實戰示範參考文檔

2.1 Log4j

        在JDK 1.3及以前,Java打日志依賴System.out.println(), System.err.println()或者e.printStackTrace(),Debug日志被寫到STDOUT流,錯誤日志被寫到STDERR流。這樣打日志有一個非常大的缺陷,即無法定制化,且日志粒度不夠細。

       于是, Gülcü 于2001年釋出了Log4j,後來成為Apache 基金會的頂級項目。Log4j 在設計上非常優秀,對後續的 Java Log 架構有長久而深遠的影響,它定義的Logger、Appender、Level等概念如今已經被廣泛使用。Log4j 的短闆在于性能,在Logback 和 Log4j2 出來之後,Log4j的使用也減少了。

2.2 J.U.L

        受Logj啟發,Sun在Java1.4版本中引入了java.util.logging,但是j.u.l功能遠不如log4j完善,開發者需要自己編寫Appenders(Sun稱之為Handlers),且隻有兩個Handlers可用(Console和File),j.u.l在Java1.5以後性能和可用性才有所提升。

2.3 J.C.L(commons.logging)

        由于項目的日志列印必然選擇兩個架構中至少一個,這時候,Apache的JCL(commons-logging)誕生了。JCL 是一個Log Facade,隻提供 Log API,不提供實作,然後有 Adapter 來使用 Log4j 或者 JUL 作為Log Implementation。

       在程式中日志建立和記錄都是用JCL中的接口,在真正運作時,會看目前ClassPath中有什麼實作,如果有Log4j 就是用 Log4j, 如果啥都沒有就是用 JDK 的 JUL。

       這樣,在你的項目中,還有第三方的項目中,大家記錄日志都使用 JCL 的接口,然後最終運作程式時,可以按照自己的需求(或者喜好)來選擇使用合适的Log Implementation。如果用Log4j, 就添加 Log4j 的jar包進去,然後寫一個 Log4j 的配置檔案;如果喜歡用JUL,就隻需要寫個 JUL 的配置檔案。如果有其他的新的日志庫出現,也隻需要它提供一個Adapter,運作的時候把這個日志庫的 jar 包加進去。

       不過,commons-logging對Log4j和j.u.l的配置問題相容的并不好,使用commons-loggings還可能會遇到類加載問題,導緻NoClassDefFoundError的錯誤出現。

Java日志架構--從入門到放棄一、寫在前面二、曆史演進 三、實戰示範參考文檔

  一切看起來很完美,做到了接口統一和實作分離,項目可以在log4j和Jul之間自由的切換,想用誰就用誰,很簡單,但是現實很殘酷。

2.4 Slf4j & Logback

        SLF4J(Simple Logging Facade for Java)和 Logback 也是Gülcü 創立的項目,目的是為了提供更高性能的實作。

        從設計模式的角度說,SLF4J 是用來在log和代碼層之間起到門面作用,類似于 JCL 的 Log Facade。對于使用者來說隻要使用SLF4J提供的接口,即可隐藏日志的具體實作,SLF4J提供的核心API是一些接口和一個LoggerFactory的工廠類,使用者隻需按照它提供的統一紀錄日志接口,最終日志的格式、紀錄級别、輸出方式等可通過具體日志系統的配置來實作,是以可以靈活的切換日志系統。

       Logback是log4j的更新版,目前分為三個目标子產品:

  • logback-core:核心子產品,是其它兩個子產品的基礎子產品
  • logback-classic:是log4j的一個改良版本,同時完整實作 SLF4J API 使你可以很友善地更換成其它日記系統如log4j 或 JDK14 Logging
  • logback-access:通路子產品與Servlet容器內建提供通過Http來通路日記的功能,是logback不可或缺的組成部分

Logback相較于log4j有更多的優點:

  • 更快的執行速度
  • 更充分的測試
  • logback-classic 非常自然的實作了SLF4J
  • 使用XML配置檔案或者Groovy
  • 自動重新載入配置檔案
  • 優雅地從I/O錯誤中恢複
  • 自動清除舊的日志歸檔檔案
  • 自動壓縮歸檔日志檔案
  • 謹慎模式
  • Lilith
  • 配置檔案中的條件處理
  • 更豐富的過濾

       到這裡,你可能會問:Apache 已經有了個JCL,用來做各種Log lib統一的接口,如果 Gülcü 要搞一個更好的 Log 實作的話,直接寫一個實作就好了,為啥還要搞一個和SLF4J呢?原因是Gülcü 認為 JCL 的 API 設計得不好,容易讓使用者寫出性能有問題的代碼。關于這點,你可以參考這篇文章獲得更詳細的介紹:https://zhuanlan.zhihu.com/p/24272450

       現在事情就變複雜了。我們有了兩個流行的 Log Facade,以及三個流行的 Log Implementation。Gülcü 是個追求完美的人,他決定讓這些Log之間都能夠友善的互相替換,是以做了各種 Adapter 和 Bridge 來連接配接:

Java日志架構--從入門到放棄一、寫在前面二、曆史演進 三、實戰示範參考文檔

       可以看到甚至 Log4j 和 JUL 都可以橋接到SLF4J,再通過 SLF4J 适配到到 Logback!需要注意的是不能有循環的橋接,比如下面這些依賴就不能同時存在:

  • jcl-over-slf4j 和 slf4j-jcl
  • log4j-over-slf4j 和 slf4j-log4j12
  • jul-to-slf4j 和 slf4j-jdk14

       然而,事情在變得更麻煩!

2.5 Log4j2

        現在有了更好的 SLF4J 和 Logback,慢慢取代JCL 和 Log4j ,事情到這裡總該大統一圓滿結束了吧。然而維護 Log4j 的人不這樣想,他們不想坐視使用者一點點被 SLF4J / Logback 蠶食,繼而搞出了 Log4j2。

        Log4j2 和 Log4j1.x 并不相容,設計上很大程度上模仿了 SLF4J/Logback,性能上也獲得了很大的提升。Log4j2 也做了 Facade/Implementation 分離的設計,分成了 log4j-api 和 log4j-core。現在好了,我們有了三個流行的Log 接口和四個流行的Log實作,如果畫出橋接關系的圖來回事什麼樣子呢?

Java日志架構--從入門到放棄一、寫在前面二、曆史演進 三、實戰示範參考文檔

三、實戰示範

3.1.Spring Boot環境

3.2. Log4j、JUL、JCL示範

3.3. Log4j2使用

3.4. sl4j 和 logback、log4j

3.5. Log4j2使用

3.6. 最佳實戰

參考文檔

[1] Java的日志架構梳理 https://www.jianshu.com/p/5326b5cc7d6c

[2]

[3]