JAVA日志框架概述


        日志用來記錄應用的運行狀態以及一些關鍵業務信息,其重要性不言而喻,通常我們借助於現有的日志框架完成日志輸出。目前開源的日志框架很多,常見的有log4j、logback等,有時候我們還會碰到諸如common-logging、slf4j這些名詞,這些框架有什么作用?它們之間有什么聯系?在搭建應用時該如何選擇合適的日志框架?對於這些問題,將會在本文中做出解釋。

一、日志門面與日志組件

        在上面提到的log4j、logback、common-logging、slf4j中,包含了2類框架,其中一類是具體用來輸出日志的框架,log4j和logback屬於此類,我們將他們稱為“日志組件”;另兩個common-logging、slf4j被歸為“日志門面”,或叫做“日志接口”。
        簡單來說,可以按照面向接口編程的思想來理解這2種組件,“日志門面”提供了標准的日志輸出API,其底層如何實現,或者說采用什么日志組件,由開發者進行選擇。當然,選擇的日志組件必須實現了對應“日志門面”的接口。

1.1.log4j與logback

        log4j隸屬於apache,其包含一個升級產品(log4j2),是目前流行的日志組件之一。logback則是近些年來才開始流行,由於其在性能上PK掉了log4j,因此越來越多的項目開始使用logback。另外JAVA的官方類庫也提供了日志組件,即JAVA UTIL LOGGING(下文簡稱JUL),這里我們不做重點討論。
        下面直接引用一段話來表述log4j和logback的性能差距:
某些關鍵操作,比如判定是否記錄一條日志語句的操作,其性能得到了顯著的提高。這個操作在LogBack中需要3納秒,而在Log4J中則需要30納秒。 
LogBack創建記錄器(logger)的速度也更快:13微秒,而在Log4J中需要23微秒。更重要的是,它獲取已存在的記錄器只需94納秒,而 Log4J需要2234納秒,時間減少到了1/23。跟JUL相比的性能提高也是顯著的。
另外,LOGBack的所有文檔是全面免費提供的,不象Log4J那樣只提供部分免費文檔而需要用戶去購買付費文檔。

1.2.common-logging與slf4j

        前文提到,這2個框架均為日志門面,但common-logging(下文簡稱JCL)隸屬於apache陣營,而slf4j與logback為同一作者。並且這兩個框架與底層日志組件的綁定機制也不相同:
  • common-logging通過動態查找的機制,在程序運行時自動找出真正使用的日志庫。由於它使用了ClassLoader尋找和載入底層的日志庫,導致了像OSGI這樣的框架無法正常工作,因為OSGI不同的插件使用自己ClassLoader。
  • slf4j編譯時靜態綁定真正的Log庫,因此可以在OSGI中使用。

二、如何集成slf4j

        在第一節中,我們解釋了日志組件和日志門面的概念,同時提到了slf4j的優越性,接下來我們將討論如何將slf4j與log4j、logback進行集成,以及如何在一個已經使用了common-logging、jul的遺留系統上無縫集成slf4j。

2.1.基本集成

        如果是一個新系統,或者你想對遺留系統的日志框架做一個完整的替換,可以引入如下依賴快速集成:
<!-- 日志組件log4j與slf4j的集成依賴 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
</dependency><!-- 日志組件logback與slf4j的集成依賴 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.7.25</version>
</dependency><!-- 日志組件jul與slf4j的集成依賴 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency><!-- 日志門面jcl與slf4j的集成依賴,將所有slf4j日志委派給jcl -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jcl</artifactId>
    <version>1.7.25</version>
</dependency>

2.2.使用橋接器

        在實際的應用中,我們會碰到不同的組件使用不同日志框架的情況, 例如Spring Framework使用的是通過日志門面commons-logging輸出日志,XSocket依賴的則是JUL。我們想統一它們的日志輸出方式以便於管理。
        slf4j提供了現成的解決方案,那便是“橋接器”,它的功能是將這些不同形式的日志打印輸出重定向到slf4j,然后slf4j又會根據綁定器把日志交給具體的日志實現工具。下面給出一個常用的應用橋接配置方案:
<!-- JUL橋接器,將jul的日志輸出重定向到slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
</dependency>
<!-- JCL橋接器,將commos-logging的日志輸出重定向到slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!--log4j橋接器,將log4j的日志輸出重定向到slf4j  -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
</dependency>
<!-- 日志組件logback與slf4j的集成依賴,各橋接器的重定向最終流向logback -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
</dependency>
        將上述依賴轉換為流程圖:
        另外,使用橋接器的時候,我們需要注意避免與2.1中的jar包混淆使用,導致日志流死循環:
條件 原因
log4j-over-slf4j.jar和slf4j-log4j12.jar同時存在 slf4j-log4j12.jar會將所有日志調用委托給log4j,而log4j-over-slf4j.jar又將所有對log4j的調用委托給相應的slf4j,兩者形成了一個死循環.
jul-to-slf4j.jar和slf4j-jdk14.jar同時存在 slf4j-jdk14.jar會將所有日志調用委托給jdk的log,而jul-to-slf4j.jar又將所有對jul-api的調用委托給相應的slf4j,兩者形成了一個死循環。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM