日志是應用軟件中不可缺少的部分,Apache的開源項目log4j是一個功能強大的日志組件,提供方便的日志記錄。在apache網站:jakarta.apache.org/log4j 可以免費下載到Log4j最新版本的軟件包。
一、入門實例
1、 新建一個Java工程,導入Log4j包,pom文件中對應的配置代碼如下:
<!-- log4j support -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、 resources目錄下創建log4j.properties文件
### 設置###
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、輸出結果
首先,控制臺輸入如下圖所示:
然后,查看/Users/duqi/logs目錄下的debug.log和error.log文件,內容分別如下,可以看出,:
- debug.log
- error.log
二、Log4J基本使用方法
Log4j由三個重要的組件構成:日志信息的優先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優先級從高到低有ERROR、WARN、 INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯 示內容
2.1 定義配置文件
其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環境。但是,使用配置文件將使您的應用程序更加靈活。Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
- 配置根Logger,其語法為:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優 先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定 義了INFO級別,則應用程序中所有DEBUG級別的日志信息將不被打印出來。 appenderName就是指把日志信息輸出到哪個地方。您可以同時指定多個輸出目的地,例如上述例子我們制定了stdout、D和E這三個地方。
- 配置文件的輸出目的地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(每天產生一個日志文件),
- org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),
- org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
- 配置日志信息的格式(布局),其語法為:
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(包含日志產生的時間、線程、類別等等信息)
Log4J采用類似C語言中的printf函數的打印格式格式化日志信息,打印參數如下:
- %m 輸出代碼中指定的消息
- %p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
- %r 輸出自應用啟動到輸出該log信息耗費的毫秒數
- %c 輸出所屬的類目,通常就是所在類的全名
- %t 輸出產生該日志事件的線程名
- %n 輸出一個回車換行符,Windows平臺為“rn”,Unix平臺為“n”
- %d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
- %l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main(TestLog4.java:10)
2.2 在代碼中使用Log4j
- 獲取記錄器
使用Log4j,第一步就是獲取日志記錄器,這個記錄器將負責控制日志信息。其語法為:public static Logger getLogger( String name)
;通過指定的名字獲得記錄器,如果必要的話,則為這個名字創建一個新的記錄器。Name一般取本類的名字,比如:static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )
。 - 讀取配置文件
當獲得了日志記錄器之后,第二步將配置Log4j環境,其語法為:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
- 插入記錄信息(格式化日志信息)
當上兩個必要步驟執行完畢,您就可以輕松地使用不同優先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;
2.3 日志級別
每個Logger都被了一個日志級別(log level),用來控制日志信息的輸出。日志級別從高到低分為:
A:off 最高等級,用于關閉所有日志記錄。
B:fatal 指出每個嚴重的錯誤事件將會導致應用程序的退出。
C:error 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。
D:warm 表明會出現潛在的錯誤情形。
E:info 一般和在粗粒度級別上,強調應用程序的運行全程。
F:debug 一般用于細粒度級別上,對調試應用程序非常有幫助。
G:all 最低等級,用于打開所有日志記錄。
上面這些級別是定義在org.apache.log4j.Level類中。Log4j只建議使用4個級別,優先級從高到低分別是error,warn,info和debug。通過使用日志級別,可以控制應用程序中相應級別日志信息的輸出。例如,如果使用b了info級別,則應用程序中所有低于info級別的日志信息(如debug)將不會被打印出來。
三、Spring中使用Log4J
一般是在web.xml配置文件中配置Log4j監聽器和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文件為例進行總結,則對應的Log4J的配置如下:
//todo
四、實戰經驗總結
在商業項目中,日志可用于數據化運營,需要記錄關鍵的業務數據;開發過程中必須準確記錄業務日志,如果丟失業務數據則是很嚴重的故障。
日志信息的打印會影響到服務的性能(吞吐量和響應時間),在業務邏輯簡單的服務中更加明顯。舉個例子,我最近負責的一個會話管理的模塊,在性能壓測的時候發現TPS只能達到250左右,被這個問題困擾了很久。首先找出性能的瓶頸:緩存操作和數據庫操作
- 發現在緩存操作中有一行打印日志的語句使用了JSON庫,例如
JSON.toJsonString(obj)
,這個對象非常復雜,導致一個讀取緩存的操作可以達到300ms左右,而實際上應該在10ms左右; - 發現數據庫操作非常耗時,但是經過分析,在系統穩定后,壓力并不是很大時,數據庫操作也比較正常;但是一旦并發數增高,則RT迅速增大,通過鏈路分析工具,查看在系統負載變高的過程中的指標發現CallAppenders()方法占據了將近40%以上的CPU時間,因此我才考慮到需要將日志級別調整為ERROR級別——不打印DEBUG級別的日志,至此,這個問題算是解決了。
本號專注于后端技術、JVM問題排查和優化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發者的工作和成長經驗,期待你能在這里有所收獲。