簡介
在系統開發中,日志是很重要的一個環節,日志寫得好對於我們開發調試,線上問題追蹤等都有很大的幫助。但記日志並不是簡單的輸出信息,需要考慮很多問題,比如日志輸出的速度,日志輸出對於系統內存,CPU的影響等,為此,出現了很多日志框架,以幫助開發者解決這些問題。
java中的常用日志框架
比較常用的有Log4j,SLF4j,Commons-logging,logback。當然,JDK本身也提供了java.util.logging包來提供對日志的支持。
Commons-loggin:是apache最早提供的日志的門面接口。它的主要作用是提供一個日志門面,使用者可以使用不同的日志實現。用戶可以自由選擇第三方的日志組件作為具體實現,像log4j,或者jdk自帶的logging, common-logging會通過動態查找的機制,在程序運行時自動找出真正使用的日志庫。common-logging內部有一個Simple logger的簡單實現,但是功能很弱。
SLF4j:是Simple Logging Facade for Java的簡稱,即java的簡單日志門面。類似於Apache Common-Logging,是對不同日志框架提供的一個門面封裝,可以在部署的時候不修改任何配置即可接入一種日志實現方案。但是,他在編譯時靜態綁定真正的Log庫。使用SLF4J時,如果你需要使用某一種日志實現,那么你必須選擇正確的SLF4J的jar包的集合(各種橋接包)。
Log4j:經典的一種日志解決方案。內部把日志系統抽象封裝成Logger 、appender 、pattern等實現。我們可以通過配置文件輕松的實現日志系統的管理和多樣化配置。pache的一個開放源代碼項目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制台、文件、GUI組件、甚至是套接口服務器、NT的事件記錄器、UNIXSyslog守護進程等;用戶也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級別,用戶能夠更加細致地控制日志的生成過程。這些可以通過一個 配置文件來靈活地進行配置,而不需要修改程序代碼。
logback:也是一種日志實現。Logback是由log4j創始人設計的又一個開源日記組件。logback當前分成三個模塊:logback-core,logback-classic和logback-access。logback-core是其它兩個模塊的基礎模塊。logback-classic是log4j的一個改良版本。此外logback-classic完整實現SLF4J API使你可以很方便地更換成其它日記系統如log4j或JDK14Logging。logback-access訪問模塊與Servlet容器集成提供通過Http來訪問日記的功能。
各個框架之間的關系
上面說了這么多日志框架,它們之間是怎樣的關系呢?
1. commons-logging和slf4j是java中的日志門面,即它們提供了一套通用的接口,具體的實現可以由開發者自由選擇。log4j和logback則是具體的日志實現方案。
2. 它們可以理解為接口與實現類的關系
3. 四個框架都可以在程序中使用,但是為了考慮擴展性,一般我們在程序開發的時候,會選擇使用commons-logging或者slf4j這些日志門面,而不是直接使用log4j或者logback這些實現。即我們寫代碼的時候導入的類一般都是來自門面框架中的類,然后將某個日志的實現框架加入到項目中,提供真正的日志輸出功能。
4. 比較常用的搭配是commons-logging+log4j,slf4j+logback
下面的圖描述的挺好:
日志框架的門面模式
門面模式,是面向對象設計模中的結構模式,又稱為外觀模式。外部與一個子系統的通信必須通過一個統一的外觀對象進行,為子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
簡單理解就是通過通過門面模式對外提供一個統一的調用接口,屏蔽子系統之間復雜的調用關系,對客戶端來講,使用起來更容易。
commons-logging和slf4j就是這樣,它們提供了日志的更高層次的抽象,具體的實現使用者不需要關心,而且可以自由選擇。
使用舉例
在開發中,我們一般不會直接使用某個具體的日志框架(比如log4j和logback),而是使用commons-logging和slf4j,這樣做的好處是,我們可以自由選擇日志實現。
特別是對於一些開源框架來說更是如此,在提供給其他人使用的時候,使用我們框架的人使用的日志框架是復雜多變的,不確定的,所以如果我們開源框架里選擇了一個具體的日志實現,而碰巧這個日志實現的可擴展性和兼容性又不好,那么使用我們開源框架的人為了滿足我們框架的日志,就只能跟我們框架用一樣的日志實現,否則打印日志可能就會有問題。這樣一來,使用我們框架的開發者的自由度就降低了。
基於commons-logging的日志使用
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class XXXService { private static final Log log = LogFactory.getLog(XXXService.class); public void doSomething(){ log.info("begin dosomething...."); } }
基於slf4j的日志使用
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class XXXService { private static final Logger logger = LoggerFactory.getLogger(XXXService.class); public void doSomething() { logger.info("begin dosomething..."); } }
上面的兩種方式,引入的包都是門面日志框架的包,而不是具體某個實現的包。
Commons-logging和SLF4j實現機制
使用門面模式,如果門面模式本身不提供日志實現,那么我們還是不能正確打印日志的。所以還需要通過門面模式能夠找到其實現類。就跟接口與實現類一樣。
那么,日志的門面框架是如何與實現框架建立關系的呢?
Commons-logging
common-logging通過動態查找的機制,在程序運行時自動找出真正使用的日志庫。由於它使用了ClassLoader尋找和載入底層的日志庫,導致了象OSGI這樣的框架無法正常工作,因為OSGI的不同的插件使用自己的ClassLoader。OSGI的這種機制保證了插件互相獨立,然而卻使Apache Commons-Logging無法工作。
SLF4j
slf4j在編譯時靜態綁定真正的Log庫,因此可以再OSGI中使用。它是通過查找類路徑下org.slf4j.impl.StaticLoggerBinder
,然后綁定工作都在這類里面進行,如果發現類路徑下有多個StaticLoggerBinder,會給出警告。
slf4j提供了針對各種日志框架的遷移方案,並未這些方案提供了各種橋接框架。
關於SLF4j,它的官方文檔講解的很好,可以參考這里
為什么要用SLF4J+Logback 替換commons-logging+log4j?
- SLF4J是編譯時綁定到具體的日志框架,性能優於采用運行時搜尋的方式的commons-logging
- SLF4J提供了更好的日志記錄方式,帶來下這幾方面的好處:1、更好的可讀性;2、不需要使用logger.isDebugEnabled()來解決日志因為字符拼接產生的性能問題。比如:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
官方文檔:這里 - logback支持了更方便的自定義日志,便於后期的日志分析,可以將日志格式化保存到各種存儲引擎中,請點擊這里 可以將日志寫入到HBase等。
補充一點
分析下面兩行代碼的區別:
logger.info("my name is {}", "medusar");
logger.info("my name is " + "medusar");
在效率上,第一行比第二行更高,因為如果當前日志級別是ERROR,第一行不會進行字符串拼接,而第二行,無論日志級別是什么,都會先進行字符串拼接。
所以為了解決這個問題,commons-logging等框架提供了下面的方式:
if (log.isDebugEnabled()){ log.debug("dddd"+"eee"); }
而slf4j卻不需要,因為它的日志級別不滿足的時候會進行字符串拼接。
參考資料
- http://www.cnblogs.com/zhuawang/p/3999235.html
- http://blog.csdn.net/yycdaizi/article/details/8276265
- https://segmentfault.com/a/1190000000370671
- http://singleant.iteye.com/blog/934593
轉自:http://blog.onlycatch.com/post/cfbc30f8d1ba