SLF4J使用和與Log4J對比

每一個Java程序員都知道日志對于任何一個Java應用程序俱饿,尤其是服務端程序是至關重要的申屹,而很多程序員也已經熟悉各種不同的日志庫如java.util.logging、Apache log4j、logback油够。

在這篇文章中肃弟,我們將學習為什么使用SLF4Jlog4j或者java.util.logging要優(yōu)秀篮幢。


SLF4J不同于其他日志類庫三椿,與其它有很大的不同。SLF4J(Simple logging Facade for Java)不是一個真正的日志實現(xiàn)伴郁,而是一個抽象層( abstraction layer)蛾绎,它允許你在后臺使用任意一個日志類庫鸦列。

當你編寫供內外部都可以使用的API或者通用類庫薯嗤,那么你真不會希望使用你類庫的客戶端必須使用你選擇的日志類庫纤泵。

如果一個項目已經使用了log4j捏题,而你加載了一個類庫,比方說 Apache Active MQ——它依賴于于另外一個日志類庫logback带射,那么你就需要把它也加載進去窟社。但如果Apache Active MQ使用了SLF4J绪钥,你可以繼續(xù)使用你的日志類庫而加載和維護一個新的日志框架程腹。

總的來說,SLF4J使你的代碼獨立于任意一個特定的日志API缀去,這是一個對于開發(fā)API的開發(fā)者很好的思想甸祭。雖然抽象日志類庫的思想已經不是新鮮的事物而且Apache commons logging也已經在使用這種思想了池户,但現(xiàn)在SLF4J正迅速成為Java世界的日志標準凡怎。讓我們再看看幾個使用SLF4J而不是log4j统倒、logback或者java.util.logging的理由房匆。

SLF4J對比Log4J浴鸿,logback和java.util.Logging的優(yōu)勢

  1. 使用SLF4J寫日志語句的主要出發(fā)點是使得你的程序獨立于任意特定的日志類庫弦追,依賴于特定類可能需要不同與你已有的配置劲件,并且導致更多維護的麻煩零远。
  2. 占位符(place holder)的使用。

在代碼中表示為{}的特性摔癣。占位符是一個非常類似于在String的format()方法中的%s供填,它會在運行時被某個提供的實際字符串所替換近她。

這不僅降低了你代碼中字符串連接次數(shù)粘捎,而且還節(jié)省了新建的String對象危彩。因為String對象是不可修改的并且它們建立在一個String池中汤徽,它們消耗堆內存( heap memory)而且大多數(shù)時間他們是不被需要的,例如當你的應用程序在生產環(huán)境以ERROR級別運行時候拼坎,一個String使用在DEBUG語句就是不被需要的。

通過使用SLF4J,你可以在運行時延遲字符串的建立债蓝,這意味著只有需要的String對象才被建立饰迹。而如果你已經使用log4j余舶,那么你已經對于在if條件中使用debug語句這種變通方案十分熟悉了欧芽,但SLF4J的占位符就比這個好用得多葛圃。

使用對比

Log4j:

if (logger.isDebugEnabled()) {
    logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}

SLF4J:

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

在SLF4J曲楚,我們不需要字符串連接而且不會導致暫時不需要的字符串消耗褥符。而是以一個以占位符和以參數(shù)傳遞實際值的模板格式下寫日志信息喷楣。你可能會在想萬一我有很多個參數(shù)怎么辦铣焊?那么你可以選擇使用變量參數(shù)版本的日志方法或者用以Object數(shù)組傳遞。這是一個相當?shù)姆奖愫透咝Х椒ǖ拇蛉罩痉椒ㄟ椿洹S涀〉涸椋谏a最終日志信息的字符串之前懈糯,這個方法會檢查一個特定的日志級別是不是打開了赚哗,這不僅降低了內存消耗而且預先降低了CPU去處理字符串連接命令的時間。這里是使用SLF4J日志方法的代碼硬萍,來自于slf4j-log4j12-1.6.1.jar中的Log4j的適配器類Log4jLoggerAdapter朴乖。

public void debug(String format, Object arg1, Object arg2) {
    if (logger.isDebugEnabled()) {
        FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
        logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
    }
}

怎么用SLF4J做Log4J的日志記錄

為了使用SLF4J买羞,你不僅需要包含SLF4J的API jar包雹食,例如 slf4j-api-1.6.1.jar吃挑,還需要相關Jar包街立,這取決于你在后臺使用的日志類庫。如果你想要使用和Log4J 一起使用SLF4J 逛犹,Simple Logging Facade for Java,,你需要包含以下的Jar包在你的classpath中梁剔,取決于哪個SLF4J和你在使用的Log4J的版本虽画。例如:

  • slf4j-api-1.5.8.jar – JAR for SLF4J API
  • log4j-1.2.16.jar – JAR for Log4J API
  • slf4j-log4j12-1.5.8.jar – Log4J Adapter for SLF4J

如果你在使用Maven去管理你的項目依賴,你只需要包含SLF4J JAR包荣病,maven會包含它的依賴的相關包码撰。為了和SLF4J一起中使用Log4J,你可以包含以下的依賴在你項目中的pom.xml众雷。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.1</version>
</dependency>
 
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.1</version>
</dependency>

使用實例

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Slf4js {
    private static Logger logger = LoggerFactory.getLogger(Slf4js.class);
    Integer t;
    Integer oldT;

    public void setTemperature(Integer temperature) {
        oldT = t;
        t = temperature;
        logger.error(" Temperature set to {}. Old temperature was {}. ", t, oldT);
        if (temperature.intValue() > 50) {
            logger.info(" Temperature has risen above 50 degrees. ");
        }
    }

    public static void main(String[] args) {
        Slf4js slf4j = new Slf4js();
        slf4j.setTemperature(1);
        slf4j.setTemperature(55);
    }
}

常見問題

1. 問題一

描述

java.lang.IllegalAccessError: tried to access field org.slf4j.impl.Static..
java.lang.IllegalAccessError: tried to access field org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory

問題原因:jar文件版本沖突

org.slf4j.impl.StaticLoggerBinderslf4j-api 中是類的公有靜態(tài)變量:

public static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

而在slf4j-log4j12(slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar其中之一)中確是私有變量:

private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

解決方案:

1.修改slf的源代碼灸拍,將這個變量有私有改為公有,再打包砾省,問題可解決鸡岗。

2.slf4j-api.jar 刪除,再導入同版本的slf4j-api-1.5.6.jar 和slf4j-log4j12-1.5.6.jar 轩性,問題可解決。

問題二

問題描述:

log4j:WARN No appenders could be found for logger (xxx.yyy.zzz).
log4j:WARN Please initialize the log4j system properly.

問題解決:

在src下面新建file名為log4j.properties內容如下:

# Configure logging for testing: optionally with log file
log4j.rootLogger=WARN, stdout
# log4j.rootLogger=WARN, stdout, logfile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

其他情形下的問題解決:

在Eclipse中開發(fā)相關項目時,在控制臺經晨又剩看到如下信息:

log4j:WARN No appenders could be found for logger
log4j:WARN Please initialize the log4j system properly.

此處輸出信息并不是錯誤信息而僅只是警告信息,因為log4j無法輸出日志,log4j是一個日志輸入軟件包。可以將Struts或Hibernate等壓縮包解壓,內有l(wèi)og4j.properties文件荤傲,將它復制到項目src文件夾或將log4j.properties放到 \WEB-INF\classes文件夾中即可。

===================================

做一個SSH項目,tomcat啟動時出現(xiàn)以下問題:

log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.

在網上查了一下,多是說把ContextLoaderListener改為SpringContextServlet,但我這樣改了沒用。后來在一個英文網站上看到一個遇到同樣問題的帖子被饿,他是這樣改的:

<context-param>
   <param-name>log4jConfigLocation</param-name>
   <param-value>/WEB-INF/config/log4j.properties</param-value>
</context-param>

······

<!-- 定義LOG4J監(jiān)聽器 -->
<listener>
   <listener-class>
org.springframework.web.util.Log4jConfigListener
   </listener-class>
</listener>

這樣改了問題就解決了,不用再修改ContextLoaderListener嗅辣。

總結

在你的開源或內部類庫中使用SLF4J會使得它獨立于任何一個特定的日志實現(xiàn)蛙奖,這意味著不需要管理多個日志配置或者多個日志類庫。

SLF4J提供了基于占位符的日志方法,不需要檢查isDebugEnabled(), isInfoEnabled()等等吹艇,提高了代碼可讀性鼻听。

通過使用SLF4J的日志方法灰羽,你可以延遲構建日志信息(Srting)的開銷恐似,直到你真正需要双藕,這對于內存和CPU都是高效的近范。

作為附注斥杜,更少的暫時的字符串意味著垃圾回收器(Garbage Collector)能夠做更多的工作,這意味著你的應用程序有為更好的吞吐量和性能返弹。

這些好處只是冰山一角师崎,你將在開始使用SL4J和閱讀其中代碼的時候知道更多的好處,建議使用SLF4J做日志而不是使用包括Log4J在內的其他日志API勺美。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坛掠,隨后出現(xiàn)的幾起案子友多,更是在濱河造成了極大的恐慌蜈抓,老刑警劉巖燕少,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碌冶,死亡現(xiàn)場離奇詭異湿痢,居然都是意外死亡,警方通過查閱死者的電腦和手機扑庞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門譬重,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人罐氨,你說我怎么就攤上這事臀规。” “怎么了栅隐?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵塔嬉,是天一觀的道長。 經常有香客問我租悄,道長谨究,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任泣棋,我火速辦了婚禮胶哲,結果婚禮上,老公的妹妹穿的比我還像新娘潭辈。我一直安慰自己鸯屿,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布把敢。 她就那樣靜靜地躺著寄摆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪修赞。 梳的紋絲不亂的頭發(fā)上婶恼,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音榔组,去河邊找鬼熙尉。 笑死,一個胖子當著我的面吹牛搓扯,可吹牛的內容都是我干的。 我是一名探鬼主播包归,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼锨推,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起换可,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤椎椰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沾鳄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慨飘,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年译荞,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓤的。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡吞歼,死狀恐怖圈膏,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情篙骡,我是刑警寧澤稽坤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站糯俗,受9級特大地震影響尿褪,放射性物質發(fā)生泄漏。R本人自食惡果不足惜得湘,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一杖玲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忽刽,春花似錦天揖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伞剑,卻和暖如春斑唬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背黎泣。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工恕刘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抒倚。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓褐着,卻偏偏與公主長得像,于是被迫代替她去往敵國和親托呕。 傳聞我的和親對象是個殘疾皇子含蓉,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • 寫Java也有一段時間了频敛,一直都有用slf4j log4j輸出日志的習慣。但是始終都是抱著“拿來主義”的態(tài)度馅扣,復制...
    Minimumy閱讀 1,374評論 1 7
  • 歷史 log4j可以當之無愧地說是Java日志框架的元老斟赚,1999年發(fā)布首個版本,2012年發(fā)布最后一個版本差油,20...
    kelgon閱讀 10,133評論 3 53
  • 前言 最近學習開java web服務器開發(fā)拗军,開始學習java,處理業(yè)務邏輯蓄喇,但對其中的日志比較好奇发侵,之前沒怎么接觸...
    九風萍舟閱讀 3,285評論 1 6
  • 概述 在項目開發(fā)中,為了跟蹤代碼的運行情況公罕,常常要使用日志來記錄信息器紧。在Java世界,有很多的日志工具庫來實現(xiàn)日志...
    靜默虛空閱讀 1,839評論 1 9
  • 一楼眷、Java日志體系概述 圖1-1 展示了Java日志體系的三個主要部分: 日志門面接口(SLF4J铲汪、JCL) 一...
    Lucky_Micky閱讀 17,632評論 0 19