[转载]为什么使用 SLF4J 而不是Log4J来做Java 日志
轉(zhuǎn)載自《http://www.oschina.net/translate/why-use-sl4j-over-log4j-for-logging》
?
每個(gè)Java開發(fā)人員都知道日志記錄對(duì)Java應(yīng)用的重要性,尤其是對(duì)服務(wù)端應(yīng)用,而且其中許多人都已經(jīng)熟悉了各種記錄日志的庫(kù),比如java.util.logging,Apache的log4j,logback,然而如果你不知道SLF4J,java的簡(jiǎn)單記錄日志的設(shè)計(jì)的話 ,那么到了學(xué)習(xí)并在你的項(xiàng)目中使用它的時(shí)候了。在這篇Java文檔里,我們將學(xué)習(xí)為什么使用SLF4J比使用log4j或者java.util.logging更好。從我寫?Java開發(fā)人員的10個(gè)記錄日志的技巧?算起已經(jīng)過去了很長(zhǎng)一段時(shí)間了。我不記得我所寫的有關(guān)日志記錄的任何事情了。無論如何,讓我們回歸到這個(gè)主題上來,與所有提到的這些日志記錄庫(kù)相比,SLF4J與它們之間有一個(gè)主要的區(qū)別。SLF4J或者說是Java的簡(jiǎn)單記錄日志設(shè)計(jì)沒有真正地實(shí)現(xiàn)日志記錄,相反它只是一個(gè)允許你使用任何處于后端的日志記錄庫(kù)的?抽象層?。如果你正在編寫內(nèi)部或者外部使用的API或者應(yīng)用庫(kù)的話,那么你真的不需要讓使用你所編寫的庫(kù)的客戶端還去選擇日志庫(kù)。假設(shè)項(xiàng)目已經(jīng)使用了log4j,而且你包含一個(gè)名為Apache Active MQ的庫(kù),這個(gè)庫(kù)還依賴于另一個(gè)日志記錄庫(kù)logback的話,那么你還需要包含它們,然而,如果Apache Active MQ使用了SLF4J的話,你可以繼續(xù)使用你的日志記錄庫(kù),而不需要痛苦地添加和維護(hù)新的日志記錄框架。簡(jiǎn)短的說,SLF4J讓你的代碼獨(dú)立于任何特定的日志記錄API,這個(gè)好的想法尤其適合于公共的API開發(fā)人員。雖然日志記錄庫(kù)的抽象理念不是新的,而且Apache的commons logging日志記錄庫(kù)也是用了這個(gè)理念,不過現(xiàn)在SLF4J很快就會(huì)成為Java世界里標(biāo)準(zhǔn)的日志記錄庫(kù)。讓我們看一些使用 SLF4J而不使用log4j,logback或者java.util.logging的理由。
?
寧愿使用SLF4J也不愿使用Log4J,logback和java.util.Logging
正如我前面所說,在你的代碼中編寫日志記錄語句使用SLF4J的主要?jiǎng)訖C(jī)是讓你的程序獨(dú)立于任何特定的日志記錄庫(kù),這些日志記錄庫(kù)可能需要與你現(xiàn)在配置不同的配置,而且還會(huì)引入更多令人頭疼的維護(hù)問題。然而除了這個(gè)之外,SLF4J API還有一個(gè)讓你使用SLF4J而不是用長(zhǎng)期感興趣的?Log4j?更讓人信服的功能,也就是占位符功能,在代碼中用{}來表示。占位符功能與?String的format()方法中?的%s非常相似,因?yàn)樗谶\(yùn)行時(shí)刻才提取所提供的真正的字符串。這不僅縮減了代碼中的許多字符串連接,而且減少了創(chuàng)建String對(duì)象所需要的資源。即便在你生產(chǎn)環(huán)境日志級(jí)別比如DEBUG和INFO級(jí)別的字符串連接可能不需要的時(shí)候,仍然可以起到同樣的效果。由于?字符串是不可更改的?,而且它們是在字符串池中創(chuàng)建的,這些字符串使用了?堆內(nèi)存?,當(dāng)應(yīng)用在生產(chǎn)環(huán)境中運(yùn)行在ERROR級(jí)別的時(shí)候,字符串在大多數(shù)情況下就不是必須的,比如DEBUG語句里的字符串就不是必須的。通過使用SLF4J,你可以延遲字符串的創(chuàng)建到運(yùn)行時(shí)刻,這意味著只有在需要字符串的時(shí)候才創(chuàng)建它。如果你已經(jīng)使用了log4j,那么你已經(jīng)熟悉把調(diào)試語句放入if()條件內(nèi)的工作場(chǎng)景,而SLF4J占位符功能比log4j更適合這種場(chǎng)景。下面是你用Log4j時(shí)的做法,當(dāng)然這并不好玩而且它增加了不必要的公式化的代碼,減少了代碼的可讀性。
if (logger.isDebugEnabled()) {logger.debug("Processing trade with id: " + id + " symbol: " + symbol); }?
而如果你使用SLF4J,你可以使用更簡(jiǎn)潔的格式達(dá)到同樣的效果,如下:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);在SLF4J中,我們不需要進(jìn)行字符串拼接,不會(huì)導(dǎo)致使用臨時(shí)字符串帶來的消耗。相反,我們使用帶占位符的模板消息來記錄日志信息,并提供實(shí)際值作為參數(shù)。也許你會(huì)想,要是有多個(gè)參數(shù)該怎么辦,你可以使用帶參數(shù)版的日志方法,也可以通過Object數(shù)組傳入。這確實(shí)是非常方便而且高效的記日志的方法。記住,在為日志信息產(chǎn)生最終的字符串之前,該方法會(huì)檢查是否開啟了特定的日志級(jí)別,這不僅降低了內(nèi)存占用,而且預(yù)先減少了執(zhí)行字符串拼接所消耗的CPU時(shí)間。下面的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());} }同樣值得了解是,日志也會(huì)對(duì)應(yīng)用程序的性能產(chǎn)生壓力,大家通常宣揚(yáng)的是只在生產(chǎn)環(huán)境中才強(qiáng)制記錄日志。
如何使用SLF4J和Log4J來做日志
除了上面所說的好處,我認(rèn)為還有個(gè)警告需要說一下,為了使用SLF4J你不僅需要進(jìn)入SLF4J API Jar包,比如slf4j-api-1.6.1.jar,還需要引入?yún)f(xié)同工作的JAR包,具體是什么jar包則依賴于后端你使用了什么日志工具庫(kù)。假如你想使用SLF4J,Simple Logging Facade for Java,還想使用Lo4J,那么你需要把下列jar包引入到你的classpath中,具體版本要視你使用的SLF4J和log4J版本而定, 比如:
slf4j-api-1.6.1.jar - JAR for SLF4J API
log4j-1.2.16.jar??? - JAR for Log4J API
slf4j-log4j12-1.6.1.jar - Log4J Adapter for SLF4J
如果你正在使用Maven來管理你的項(xiàng)目依賴,你可以只引入SLF4J JAR,然后maven會(huì)引入它所依賴的其它JAR包。為了使用Log4J和SLF4J,你可以在你項(xiàng)目的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>?
順便說一下,如果你對(duì)使用帶參數(shù)版的日志方法感興趣,那就需要引入SLF4J 1.7版本。
?
如何使用SLF4J和Logback來做日志
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><scope>compile</scope> </dependency> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><scope>test</scope> </dependency> 具體的配置例子: <?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%date %level [%thread] %logger [%file : %line] %msg%n</pattern><charset>UTF-8</charset></encoder></appender><logger name="org" level="INFO" /><root level="ALL"><appender-ref ref="stdout" /></root> </configuration>含義:<root>也是其實(shí)是一個(gè)name=root的logger,就是一個(gè)子節(jié)點(diǎn)。是所有root的父節(jié)點(diǎn)。
<logger name="org" level="INFO" />會(huì)接管org包下的日志,沒有設(shè)置appender,表示此loger本身不打印任何信息;沒有設(shè)置addtivity,默認(rèn)為true,將此loger的打印信息向上級(jí)傳遞;但是只傳遞INFO級(jí)別(TRACE < DEBUG < INFO < WARN < ERROR)到root節(jié)點(diǎn)處理。
<root> 節(jié)點(diǎn)處理所有級(jí)別的輸出,并將其全部輸出到控制臺(tái)。
在需要使用的類中:private final static Logger LOGGER = LoggerFactory.getLogger(LogProcessorImpl.class);
注意打出異常堆棧
//可以打出e的異常堆棧LOGGER.error("write to json string error: {}", paramBean, e);//無法打出堆棧LOGGER.error("write to json string error: {}, {}", paramBean, e);?
參考《http://www.cnblogs.com/cb0327/p/5759441.html》
《http://www.cnblogs.com/warking/p/5710303.html》
轉(zhuǎn)載于:https://www.cnblogs.com/wangrd/articles/6953135.html
總結(jié)
以上是生活随笔為你收集整理的[转载]为什么使用 SLF4J 而不是Log4J来做Java 日志的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LZW算法PHP实现方法 lzw_dec
- 下一篇: 21、Java并发性和多线程-Java中