1. 程式人生 > >SLF4J 簡單日誌門面 介紹和使用

SLF4J 簡單日誌門面 介紹和使用

ews 靈活 common 滿足 ID don 路徑 CA 無奈

參考:http://singleant.iteye.com/blog/934593 http://liuzidong.iteye.com/blog/776072

介紹

簡單日記門面(simple logging Facade for java)SLF4J是為各種loging APIs提供一個簡單統一的接口,從而使得最終用戶能夠在部署的時候配置自己希望的loging APIs實現。 Logging API實現既可以選擇直接實現SLF4J接的loging APIs如: NLOG4J、SimpleLogger。也可以通過SLF4J提供的API實現來開發相應的適配器如Log4jLoggerAdapter、JDK14LoggerAdapter。在SLF4J發行版本中包含了幾個jar包,如slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-log4j13.jar, slf4j-jdk14.jar and slf4j-jcl.jar通過這些jar文件可以使編譯期與具體的實現脫離。或者說可以靈活的切換,我們在開發過程中可能使用各種log,每個Log有不同的風格、布局,如果想靈活的切換那麽slf4j是比較好的選擇。SLF4J不是具體的日誌解決方案,它只服務於各種各樣的日誌系統。按照官方的說法,SLF4J是一個用於日誌系統的簡單Facade,允許最終用戶在部署其應用時使用其所希望的日誌系統。



一、 概念

Log4j
Apache的一個開放源代碼項目,通過使用Log4j,我們可以控制日誌信息輸送的目的地是控制臺、文件、GUI組件、甚至是套接口服務 器、NT的事件記錄器、UNIX Syslog守護進程等;用戶也可以控制每一條日誌的輸出格式;通過定義每一條日誌信息的級別,用戶能夠更加細致地控制日誌的生成過程。這些可以通過一個 配置文件來靈活地進行配置,而不需要修改程序代碼。是 經典的一種日誌解決方案。內部把日誌系統抽象封裝成Logger 、appender 、pattern 等實現。我們可以通過配置文件輕松的實現日誌系統的管理和多樣化配置。

LOGBack
Logback是由log4j創始人設計的又一個開源日記組件。logback當前分成三個模塊:logback-core,logback- classic和logback-access。logback-core是其它兩個模塊的基礎模塊。logback-classic是log4j的一個 改良版本。此外logback-classic完整實現SLF4J API使你可以很方便地更換成其它日記系統如log4j或JDK14 Logging。logback-access訪問模塊與Servlet容器集成提供通過Http來訪問日記的功能。

LOGBack 作為一個通用可靠、快速靈活的日誌框架,將作為Log4j 的替代和SLF4J 組成新的日誌系統的完整實現。官網上稱具有極佳的性能,在關鍵路徑上執行速度是log4j 的10 倍,且內存消耗更少。具體優勢見:http://logback.qos.ch/reasonsToSwitch.html

Log4J vs. LOGBack
LOGBack作為一個通用可靠、快速靈活的日誌框架,將作為Log4j的替代和SLF4J組成新的日誌系統的完整實現。LOGBack聲稱具有極佳的性能,“ 某些關鍵操作,比如判定是否記錄一條日誌語句的操作,其性能得到了顯著的提高。這個操作在LogBack中需要3納秒,而在Log4J中則需要30納秒。 LogBack創建記錄器(logger)的速度也更快:13微秒,而在Log4J中需要23微秒。更重要的是,它獲取已存在的記錄器只需94納秒,而 Log4J需要2234納秒,時間減少到了1/23。跟JUL相比的性能提高也是顯著的”。


另外,LOGBack的所有文檔是全面免費提供的,不象Log4J那樣只提供部分免費文檔而需要用戶去購買付費文檔。

SLF4J
簡單日記門面(Facade)SLF4J是為各種loging APIs提供一個簡單統一的接口,從而使得最終用戶能夠在部署的時候配置自己希望的loging APIs實現。 Logging API實現既可以選擇直接實現SLF4J接的loging APIs如: NLOG4J、SimpleLogger。也可以通過SLF4J提供的API實現來開發相應的適配器如Log4jLoggerAdapter、JDK14LoggerAdapter。

Apache Common-Logging
目前廣泛使用的Java日誌門面庫。通過動態查找的機制,在程序運行時自動找出真正使用的日誌庫。但由於它使用了ClassLoader尋找和載入底層的日誌庫, 導致了象OSGI這樣的框架無法正常工作,由於其不同的插件使用自己的ClassLoader。 OSGI的這種機制保證了插件互相獨立,然而確使Apache Common-Logging無法工作。 apache最早提供的日誌的門面接口。避免和具體的日誌方案直接耦合。類似於JDBC 的api 接口,具體的的JDBC driver 實現由各數據庫提供商實現。通過統一接口解耦,不過其內部也實現了一些簡單日誌方案。

SLF4J vs. Apache Common-Logging
SLF4J庫類似於Apache Common-Logging。但是,他在編譯時靜態綁定真正的Log庫。使用SLF4J時,如果你需要使用某一種日誌實現,那麽你必須選擇正確的SLF4J的jar包的集合。 如此便可以在OSGI中使用了。
另外,SLF4J 支持參數化的log字符串,避免了之前為了減少字符串拼接的性能損耗而不得不寫的if(logger.isDebugEnable()),現在你可以直接寫:logger.debug(“current user is: {}”, user)。拼裝消息被推遲到了它能夠確定是不是要顯示這條消息的時候,但是獲取參數的代價並沒有幸免。同時,日誌中的參數若超過三個,則需要將參數以數組的形式傳入,如:
Object[] params = {value1, value2, value3};
logger.debug(“first value: {}, second value: {} and third value: {}.”, params);


現在,Hibernate、Jetty、Spring-OSGi、Wicket和MINA等項目都已經遷移到了SLF4J,由此可見SLF4J的影響力不可忽視。


Slf4j全稱為Simple Logging Facade for JAVA:java簡單日誌門面。 是對不同日誌框架提供的一個門面封裝。可以在部署的時候不修改任何配置即可接入一種日誌實現方案。和commons-loging 應該有一樣的初衷。個人感覺設從計上更好一些,沒有commons 那麽多潛規則。同時有兩個額外特點:

1. 能支持多個參數,並通過{} 占位符進行替換,避免老寫logger.isXXXEnabled 這種無奈的判斷,帶來性能提升見:http://www.slf4j.org/faq.html#logging_performance 。

2.OSGI 機制更好兼容支持,官網上的一個圖:

技術分享圖片

從上圖可以發現,選擇還是很多的。

二、 常見日誌方案和註意事項

1.Commons-logging+log4j : 經典的一個日誌實現方案。出現在各種框架裏。如spring 、webx 、ibatis 等等。直接使用log4j 即可滿足我們的日誌方案。但是一般為了避免直接依賴具體的日誌實現,一般都是結合commons-logging 來實現。常見代碼如下:

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

private static Log logger = LogFactory.getLog(CommonsLoggingTest.class);

代碼上,沒有依賴任何的log4j 內部的類。那麽log4j 是如何被裝載的?

Log 是一個接口聲明。LogFactory 的內部會去裝載具體的日誌系統,並獲得實現該Log 接口的實現類。而內部有一個Log4JLogger 實現類對Log 接口同時內部提供了對log4j logger 的代理。LogFactory 內部裝載日誌系統流程:

1. 首先,尋找org.apache.commons.logging.LogFactory 屬性配置

2. 否則,利用JDK1.3 開始提供的service 發現機制,會掃描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory 文件,若找到則裝載裏面的配置,使用裏面的配置。

3. 否則,從Classpath 裏尋找commons-logging.properties ,找到則根據裏面的配置加載。

4. 否則,使用默認的配置:如果能找到Log4j 則默認使用log4j 實現,如果沒有則使用JDK14Logger 實現,再沒有則使用commons-logging 內部提供的SimpleLog 實現。

從上述加載流程來看,如果沒有做任何配置,只要引入了log4j 並在classpath 配置了log4j.xml ,則commons-logging 就會使log4j 使用正常,而代碼裏不需要依賴任何log4j 的代碼。


2.Commons-logging+log4j+slf4j

如果在原有commons-logging 系統裏,如果要遷移到slf4j, 使用slf4j 替換commons-logging ,也是可以做到的。原理使用到了上述commons-logging 加載的第二點。需要引入Org.slf4j.jcl-over-slf4j-1.5.6.jar 。這個jar 包提供了一個橋接,讓底層實現是基於slf4j 。原理是在該jar 包裏存放了配置META-INF/services/org.apache.commons.logging.LogFactory =org.apache.commons.logging.impl.SLF4JLogFactory,而commons-logging 在初始化的時候會找到這個serviceId ,並把它作為LogFactory 。

完成橋接後,那麽那麽簡單日誌門面SLF4J 內部又是如何來裝載合適的log 呢?

原理是SLF4J 會在編譯時會綁定import org.slf4j.impl.StaticLoggerBinder; 該類裏面實現對具體日誌方案的綁定接入。任何一種基於slf4j 的實現都要有一個這個類。如:

org.slf4j.slf4j-log4j12-1.5.6: 提供對 log4j 的一種適配實現。

Org.slf4j.slf4j-simple-1.5.6: 是一種 simple 實現,會將 log 直接打到控制臺。

……

那麽這個地方就要註意了:如果有任意兩個實現slf4j 的包同時出現,那就有可能釀就悲劇,你可能會發現日誌不見了、或都打到控制臺了。原因是這兩個jar 包裏都有各自的org.slf4j.impl.StaticLoggerBinder ,編譯時候綁定的是哪個是不確定的。這個地方要特別註意!!出現過幾次因為這個導致日誌錯亂的問題。

3.使用SLf4j 很簡單:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestSlf4j {
private static final Logger logger = LoggerFactory.getLogger(TestSlf4j.class);
public static void main(String[] args) {
logger.info(logger.getName());
}
}

代碼裏也看不到任何具體日誌實現方案的痕跡。


SLF4J 簡單日誌門面 介紹和使用