日志是應(yīng)用軟件中不可缺少的部分,Apache的開源項(xiàng)目log4j是一個(gè)功能強(qiáng)大的日志組件,提供方便的日志記錄。在apache網(wǎng)站:jakarta.apache.org/log4j 可以免費(fèi)下載到Log4j最新版本的軟件包。
一、入門實(shí)例
1、 新建一個(gè)Java工程,導(dǎo)入Log4j包,pom文件中對應(yīng)的配置代碼如下:
<!-- log4j support -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、 resources目錄下創(chuàng)建log4j.properties文件
### 設(shè)置###
log4j.rootLogger = debug,stdout,D,E
### 輸出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 輸出DEBUG 級別以上的日志到=/home/duqi/logs/debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = /home/duqi/logs/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 輸出ERROR 級別以上的日志到=/home/admin/logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =/home/admin/logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
3、輸出日志的例子如下
package com.javadu.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log4JTest {
private static final Logger logger = LoggerFactory.getLogger(Log4JTest.class);
public static void main(String[] args) {
// 記錄debug級別的信息
logger.debug("This is debug message.");
// 記錄info級別的信息
logger.info("This is info message.");
// 記錄error級別的信息
logger.error("This is error message.");
}
}
4、輸出結(jié)果
首先,控制臺輸入如下圖所示:

然后,查看/Users/duqi/logs目錄下的debug.log和error.log文件,內(nèi)容分別如下,可以看出,:
debug.log

error.log

二、Log4J基本使用方法
Log4j由三個(gè)重要的組件構(gòu)成:日志信息的優(yōu)先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優(yōu)先級從高到低有ERROR、WARN、 INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯 示內(nèi)容
2.1 定義配置文件
其實(shí)您也可以完全不使用配置文件,而是在代碼中配置Log4j環(huán)境。但是,使用配置文件將使您的應(yīng)用程序更加靈活。Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
1.配置根Logger,其語法為:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志記錄的優(yōu)先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個(gè)級別,優(yōu) 先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應(yīng)用程序中相應(yīng)級別的日志信息的開關(guān)。比如在這里定 義了INFO級別,則應(yīng)用程序中所有DEBUG級別的日志信息將不被打印出來。 appenderName就是指把日志信息輸出到哪個(gè)地方。您可以同時(shí)指定多個(gè)輸出目的地,例如上述例子我們制定了stdout、D和E這三個(gè)地方。
2.配置文件的輸出目的地Appender,一般,配置代碼的格式如下
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
…
log4j.appender.appenderName.option = valueN
其中,Log4j提供的appender有以下幾種:
- org.apache.log4j.ConsoleAppender(控制臺),
- org.apache.log4j.FileAppender(文件),
- org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件),
- org.apache.log4j.RollingFileAppender(文件大小到達(dá)指定尺寸的時(shí)候產(chǎn)生一個(gè)新的文件),
- org.apache.log4j.WriterAppender(將日志信息以流格式發(fā)送到任意指定的地方)
3.配置日志信息的格式(布局),其語法為:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
…
log4j.appender.appenderName.layout.option = valueN
其中,Log4j提供的layout有以下幾種:
- org.apache.log4j.HTMLLayout(以HTML表格形式布局),
- org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
- org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
- org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線程、類別等等信息)
Log4J采用類似C語言中的printf函數(shù)的打印格式格式化日志信息,打印參數(shù)如下:
- %m 輸出代碼中指定的消息
- %p 輸出優(yōu)先級,即DEBUG,INFO,WARN,ERROR,F(xiàn)ATAL
- %r 輸出自應(yīng)用啟動(dòng)到輸出該log信息耗費(fèi)的毫秒數(shù)
- %c 輸出所屬的類目,通常就是所在類的全名
- %t 輸出產(chǎn)生該日志事件的線程名
- %n 輸出一個(gè)回車換行符,Windows平臺為“rn”,Unix平臺為“n”
- %d 輸出日志時(shí)間點(diǎn)的日期或時(shí)間,默認(rèn)格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
- %l 輸出日志事件的發(fā)生位置,包括類目名、發(fā)生的線程,以及在代碼中的行數(shù)。舉例:Testlog4.main(TestLog4.java:10)
2.2 在代碼中使用Log4j
1.獲取記錄器
使用Log4j,第一步就是獲取日志記錄器,這個(gè)記錄器將負(fù)責(zé)控制日志信息。其語法為:public static Logger getLogger( String name);通過指定的名字獲得記錄器,如果必要的話,則為這個(gè)名字創(chuàng)建一個(gè)新的記錄器。Name一般取本類的名字,比如:static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )。
2.讀取配置文件
當(dāng)獲得了日志記錄器之后,第二步將配置Log4j環(huán)境,其語法為:
BasicConfigurator.configure (): 自動(dòng)快速地使用缺省Log4j環(huán)境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.插入記錄信息(格式化日志信息)
當(dāng)上兩個(gè)必要步驟執(zhí)行完畢,您就可以輕松地使用不同優(yōu)先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;
2.3 日志級別
每個(gè)Logger都被了一個(gè)日志級別(log level),用來控制日志信息的輸出。日志級別從高到低分為:
A:off 最高等級,用于關(guān)閉所有日志記錄。
B:fatal 指出每個(gè)嚴(yán)重的錯(cuò)誤事件將會導(dǎo)致應(yīng)用程序的退出。
C:error 指出雖然發(fā)生錯(cuò)誤事件,但仍然不影響系統(tǒng)的繼續(xù)運(yùn)行。
D:warm 表明會出現(xiàn)潛在的錯(cuò)誤情形。
E:info 一般和在粗粒度級別上,強(qiáng)調(diào)應(yīng)用程序的運(yùn)行全程。
F:debug 一般用于細(xì)粒度級別上,對調(diào)試應(yīng)用程序非常有幫助。
G:all 最低等級,用于打開所有日志記錄。
上面這些級別是定義在org.apache.log4j.Level類中。Log4j只建議使用4個(gè)級別,優(yōu)先級從高到低分別是error,warn,info和debug。通過使用日志級別,可以控制應(yīng)用程序中相應(yīng)級別日志信息的輸出。例如,如果使用b了info級別,則應(yīng)用程序中所有低于info級別的日志信息(如debug)將不會被打印出來。
三、Spring中使用Log4J
一般是在web.xml配置文件中配置Log4j監(jiān)聽器和log4j.properties文件,代碼如下:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:/config/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
在之前的Spring In Action系列文章中,我都是以Java Config文件為例進(jìn)行總結(jié),則對應(yīng)的Log4J的配置如下:
//todo
四、實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)
在商業(yè)項(xiàng)目中,日志可用于數(shù)據(jù)化運(yùn)營,需要記錄關(guān)鍵的業(yè)務(wù)數(shù)據(jù);開發(fā)過程中必須準(zhǔn)確記錄業(yè)務(wù)日志,如果丟失業(yè)務(wù)數(shù)據(jù)則是很嚴(yán)重的故障。
日志信息的打印會影響到服務(wù)的性能(吞吐量和響應(yīng)時(shí)間),在業(yè)務(wù)邏輯簡單的服務(wù)中更加明顯。舉個(gè)例子,我最近負(fù)責(zé)的一個(gè)會話管理的模塊,在性能壓測的時(shí)候發(fā)現(xiàn)TPS只能達(dá)到250左右,被這個(gè)問題困擾了很久。首先找出性能的瓶頸:緩存操作和數(shù)據(jù)庫操作
- 發(fā)現(xiàn)在緩存操作中有一行打印日志的語句使用了JSON庫,例如JSON.toJsonString(obj),這個(gè)對象非常復(fù)雜,導(dǎo)致一個(gè)讀取緩存的操作可以達(dá)到300ms左右,而實(shí)際上應(yīng)該在10ms左右;
- 發(fā)現(xiàn)數(shù)據(jù)庫操作非常耗時(shí),但是經(jīng)過分析,在系統(tǒng)穩(wěn)定后,壓力并不是很大時(shí),數(shù)據(jù)庫操作也比較正常;但是一旦并發(fā)數(shù)增高,則RT迅速增大,通過鏈路分析工具,查看在系統(tǒng)負(fù)載變高的過程中的指標(biāo)發(fā)現(xiàn)CallAppenders()方法占據(jù)了將近40%以上的CPU時(shí)間,因此我才考慮到需要將日志級別調(diào)整為ERROR級別——不打印DEBUG級別的日志,至此,這個(gè)問題算是解決了。
歡迎加入QQ群:104286694