log4j的基本使用和引數設定

bingguang1993發表於2018-03-22

1、簡介

apache的一個開放原始碼專案。

精確控制日誌的輸出,包括輸出的格式,輸出的目的地,輸出的過濾(不同級別日誌的輸出)等。

配置簡單,不需要在程式碼中配置環境,支援兩種配置檔案格式,XML和Java特性檔案(鍵=值,常見的.properties),常用後者如 log4j.properties




2、核心元件

Log4j中有三個主要的元件,它們分別是 Logger、Appender和Layout。

Log4j 允許開發人員定義多個Logger,每個Logger擁有自己的名字,Logger之間通過名字來表明隸屬關係。有一個Logger稱為Root,它永遠存在,且不能通過名字檢索或引用,可以通過Logger.getRootLogger()方法獲得,其它Logger通過 Logger.getLogger(String name)方法。

Appender則是用來指明將所有的log資訊存放到什麼地方,Log4j中支援多種appender,如 console、files、GUI components、NT Event Loggers等,一個Logger可以擁有多個Appender,也就是你既可以將Log資訊輸出到螢幕,同時儲存到一個檔案中。

Layout的作用是控制Log資訊的輸出方式,也就是格式化輸出的資訊。

Log4j中將要輸出的Log資訊定義了5種級別,依次為DEBUG、INFO、WARN、ERROR和FATAL,當輸出時,只有級別高過配置中規定的級別的資訊才能真正的輸出,這樣就很方便的來配置不同情況下要輸出的內容,而不需要更改程式碼。

2.1 Logger

公共類Logger, 負責處理日誌記錄的大部分操作。

日誌記錄器(Logger)將只輸出那些級別高於或等於它的級別的資訊。如果沒有設定日誌記錄器(Logger)的級別,那麼它將會繼承最近的祖先的級別

例如在包com.foo.bar中建立一個日誌記錄器(Logger)並且沒有設定級別,那它將會繼承在包com.foo中建立的日誌記錄器(Logger)的級別。如果在com.foo中沒有建立日誌記錄器(Logger)的話,那麼在com.foo.bar中建立的日誌記錄器(Logger)將繼承root日誌記錄器(Logger)的級別。

可以為日誌指定不同的級別,級別從低到高支援以下幾種:
ALL    開啟所有日誌
DEBUG    細粒度資訊事件,對除錯應用程式是非常有幫助的    
INFO    粗粒度資訊事件,突出強調應用程式的執行過程    
WARN    可能出現潛在錯誤的情形    
ERROR    雖然發生錯誤事件,但仍然不影響系統的繼續執行    
FATAL    指出每個嚴重的錯誤事件將會導致應用程式的退出
OFF    關閉所有日誌

比較常用的Logger建立方法,就是根據類名例項化一個靜態的全域性日誌記錄器:
  1. static Logger logger = Logger.getLogger(test.class);

日誌記錄器都可以用下面方法設定級別: 
  1. logger.setLevel((Level)Level.WARN);

當然,這是程式碼設定的方式。我們剛才提到過,可以使用配置檔案的方式進行配置,那麼我們後面會提到。

2.2 Appender

公共介面Appender,負責控制日誌記錄操作的輸出。

下面是API中提供的輸出方式(常用的見紅字),也可以自己實現Appender介面,建立以自己的方式進行日誌輸出的Appender:
ConsoleAppender使用使用者指定的佈局(layout)輸出日誌事件到System.out或者 System.err。預設的目標是System.out
FileAppender把日誌事件寫入一個檔案
DailyRollingFileAppender擴充套件FileAppender,因此多個日誌檔案可以以一個使用者選定的頻率進行迴圈日誌記錄
RollingFileAppender擴充套件FileAppender,備份容量達到一定大小的日誌檔案
WriterAppender根據使用者的選擇把日誌事件寫入到Writer或者OutputStream
SMTPAppender當特定的日誌事件發生時,一般是指發生錯誤或者重大錯誤時,傳送一封郵件
SocketAppender給遠端日誌伺服器(通常是網路套接位元組點)傳送日誌事件(LoggingEvent)物件
SocketHubAppender給遠端日誌伺服器群組(通常是網路套接位元組點)傳送日誌事件(LoggingEvent)物件
SyslogAppender給遠端非同步日誌記錄的後臺精靈程式(daemon)傳送訊息
TelnetAppender一個專用於向只讀網路套接字傳送訊息的log4j appender

2.3 Layout

公共抽象類,負責格式化Appender的輸出。

Appender必須使用一個與之相關聯的 Layout,這樣它才能知道怎樣格式化它的輸出。

log4j常見的三種型別的Layout:
HTMLLayout格式化日誌輸出為HTML表格
PatternLayout根據指定的轉換模式格式化日誌輸出,或者如果沒有指定任何轉換模式,就使用預設的轉換模式
SimpleLayout以一種非常簡單的方式格式化日誌輸出,它列印級別 Level,然後跟著一個破折號“-“ ,最後才是日誌訊息
 


3、配置檔案的設定

3.1 根 Logger

  1. log4j.rootLogger = [ level ] , appenderName, appenderName, ...
  • level  優先順序,ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF 
  • appenderName  指定日誌資訊輸出到哪個地方。您可以同時指定多個輸出目的地

3.2 某個包或類的 Logger

之前我們提到過,日誌記錄器(Logger)將只輸出那些級別高於或等於它的級別的資訊,如果沒有設定日誌記錄器(Logger)的級別,那麼它將會繼承最近的祖先的級別。

假如你在配置檔案中沒有針對有些包或者類進行單獨的級別設定,那麼它會直接繼承最近祖先的級別,依次往上如果都沒有那麼最終會繼承 RootLogger 根日誌記錄器的級別。

配置語法如下:
  1. log4j.logger.xxx.xxx.xxx=level

這裡的xxx.xxx可以是包,比如com.greejoy;也可以是具體的類,比如com.greejoy.action.LoginAction

示例:
  1. log4j.rootLogger=WARN,A
  2. log4j.logger.com.opensymphony.xwork2.interceptor.TimerInterceptor=DEBUG
  3. log4j.appender.A=org.apache.log4j.ConsoleAppender
  4. log4j.appender.A.layout=org.apache.log4j.PatternLayout
  5. log4j.appender.A.layout.ConversionPattern==%-d{yyyy-MM-dd HH:mm:ss} [%p]-[%c] %m%n

假如現在有類indiv.dulk.wechat.InitWechatServlet,此處沒有配置level,預設繼承到了根Logger的level,即WARN。此時如果類中有log輸出語句如下:
  1. log.info("微信accessToken重新整理 " + WechatAPI.getAccessToken());

最終在控制檯是不會輸出的,因為INFO的等級比WARN等級低,不會輸出。如果我們改下配置檔案:
  1. log4j.rootLogger=WARN,A
  2. log4j.logger.indiv.dulk=DEBUG
  3. log4j.logger.com.opensymphony.xwork2.interceptor.TimerInterceptor=DEBUG
  4. log4j.appender.A=org.apache.log4j.ConsoleAppender
  5. log4j.appender.A.layout=org.apache.log4j.PatternLayout
  6. log4j.appender.A.layout.ConversionPattern==%-d{yyyy-MM-dd HH:mm:ss} [%p]-[%c] %m%n

定義了indiv.dulk包level為DEBUG,indiv.dulk.wechat.InitWechatServlet沒有單獨設定level,往上找最終繼承indiv.dulk的level,即DEBUG,此時剛才的log輸出語句就會輸出在控制檯上。因為INFO的等級比DEBUG的等級高。

回顧下等級大小:
ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF

需要注意的是單獨配置的類或包,都是受全域性管理的,意思就是說,除了滿足單獨配置Logger要求的日誌會輸出,同時滿足根配置Logger的日誌也會輸出

這就給我們帶來了麻煩,假如都設定在控制檯輸出,只是單獨配置的Logger格式設定不一樣,那麼在控制檯你會看到內容相仿的兩條日誌輸出。

也就是說,假如我們有如下配置檔案,最終會出現如下的情況:
  1. log4j.rootLogger=WARN,A
  2. log4j.logger.indiv.dulk.wechat=DEBUG,wechat
  3. log4j.appender.A=org.apache.log4j.ConsoleAppender
  4. log4j.appender.A.layout=org.apache.log4j.PatternLayout
  5. log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p]-[%c] %m%n
  6. log4j.appender.wechat=org.apache.log4j.ConsoleAppender
  7. log4j.appender.wechat.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.wechat.layout.ConversionPattern=[%p]-[%c] %m%n
 
這顯然不是我們想要的,所以需要改下配置,讓指定的包不受全域性管理
  1. log4j.rootLogger=WARN,A
  2. log4j.logger.indiv.dulk.wechat=DEBUG,wechat
  3. #不受全域性管理
  4. log4j.additivity.indiv.dulk.wechat=false
  5. log4j.appender.A=org.apache.log4j.ConsoleAppender
  6. log4j.appender.A.layout=org.apache.log4j.PatternLayout
  7. log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p]-[%c] %m%n
  8. log4j.appender.wechat=org.apache.log4j.ConsoleAppender
  9. log4j.appender.wechat.layout=org.apache.log4j.PatternLayout
  10. log4j.appender.wechat.layout.ConversionPattern=[%p]-[%c] %m%n
 
這樣,就得到了我們想要的結果。

3.3 日誌輸出地址 Appender

  1. log4j.appender.appenderName = fully.qualified.name.of.appender.class (有資格的appender類的全名)
  2. log4j.appender.appenderName.option1 = value1
  3. 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(將日誌資訊以流格式傳送到任意指定的地方)

3.4 日誌輸出格式 Layout

  1. log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
  2. log4j.appender.appenderName.layout.option1 = value1
  3. 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(包含日誌產生的時間、執行緒、類別等等資訊)

列印的引數設定示例:
  1. log4j.appender.log.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t ] %m%n
  • %m   輸出程式碼中指定的訊息
  • %p   輸出優先順序,即DEBUG,INFO,WARN,ERROR,FATAL
  • %r   輸出自應用啟動到輸出該log資訊耗費的毫秒數
  • %c   輸出所屬的類目,通常就是所在類的全名
  • %t   輸出產生該日誌事件的執行緒名
  • %n   輸出一個回車換行符,Windows平臺為“/r/n”,Unix平臺為“/n”
  • %d   輸出日誌時間點的日期或時間。預設格式為ISO8601,也可以在其後指定格式。比如:%d{yyy MMM dd HH:mm:ss , SSS},輸出類似:2002年10月18日 22:10:28, 921
  • %l   輸出日誌事件的發生位置,包括類目名、發生的執行緒,以及在程式碼中的行數
 

3.5 配置示例

示例1:
  1. ### 設定###
  2. log4j.rootLogger = debug,stdout,D,E
  3. ### 輸出資訊到控制檯 ###
  4. log4j.appender.stdout = org.apache.log4j.ConsoleAppender
  5. log4j.appender.stdout.Target = System.out
  6. log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
  7. log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
  8. ### 輸出DEBUG 級別以上的日誌到=E://logs/error.log ###
  9. log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
  10. log4j.appender.D.File = E://logs/log.log
  11. log4j.appender.D.Append = true
  12. log4j.appender.D.Threshold = DEBUG
  13. log4j.appender.D.layout = org.apache.log4j.PatternLayout
  14. log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
  15. ### 輸出ERROR 級別以上的日誌到=E://logs/error.log ###
  16. log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
  17. log4j.appender.E.File =E://logs/error.log
  18. log4j.appender.E.Append = true
  19. log4j.appender.E.Threshold = ERROR
  20. log4j.appender.E.layout = org.apache.log4j.PatternLayout
  21. log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

注意:例如 log4j.appender.log.Threshold = ERROR 表示在總控開關的前提,覺得精確,只有達到這個級別的日誌才被記錄到這個檔案中

示例2:
  1. #指定目錄下包下的日誌資訊都存放到資料庫
  2. log4j.logger.database=DEBUG,oracledb
  3. log4j.appender.oracledb=org.apache.log4j.jdbc.JDBCAppender
  4. log4j.appender.oracledb.Driver=oracle.jdbc.driver.OracleDriver
  5. log4j.appender.oracledb.URL=jdbc:oracle:thin:@192.168.20.92:1521:chshsid(切忌此處為sid而不是資料庫名)
  6. log4j.appender.oracledb.user=scott
  7. log4j.appender.oracledb.password=tiger
  8. #log4j.appender.encoding=utf-8
  9. log4j.appender.oracledb.sql=INSERT INTO enter_ora_log4j VALUES ('%d{yyyy-MM-dd HH:mm:ss}', '%t', '%p', '%l', '%m')
  10. log4j.appender.oracledb.layout=org.apache.log4j.PatternLayout

示例3:
  1. #指定目錄下的java類的日誌資訊都存放到該目錄下
  2. log4j.logger.com.cuigq.TestError=DEBUG,R2
  3. log4j.appender.R2=org.apache.log4j.DailyRollingFileAppender
  4. log4j.appender.R2.File=d:/loginfo/html.html
  5. #log4j.appender.R2.MaxFileSize=500KB
  6. #log4j.appender.R2.MaxBackupIndex=1
  7. log4j.appender.R2.layout=org.apache.log4j.HTMLLayout
  8. #log4j.appender.R2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n

示例4:
  1. #指定目錄下包下的日誌資訊都存放到該目錄下
  2. log4j.logger.cn.com.cuigq.Theard=DEBUG,R1
  3. log4j.appender.R1=org.apache.log4j.RollingFileAppender
  4. log4j.appender.R1.File=d:/loginfo/iamSystem1.log
  5. log4j.appender.R1.MaxFileSize=500KB
  6. log4j.appender.R1.MaxBackupIndex=1
  7. log4j.appender.R1.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.R1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n



4、基本使用 和 Web下的使用

4.1 基本步驟流程

4.1.1 得到日誌記錄器Logger

使用Log4j,第一步就是獲取日誌記錄器,這個記錄器將負責控制日誌資訊。其語法為:
  1. public static Logger getLogger( String name)

通過指定的名字獲得記錄器,如果必要的話,則為這個名字建立一個新的記錄器。Name一般取本類的名字,比如:
  1. static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName ())

4.1.2 讀取配置檔案

當獲得了日誌記錄器之後,第二步將配置Log4j環境,其語法為:
  1. BasicConfigurator.configure (): 自動快速地使用預設Log4j環境
  2. PropertyConfigurator.configure (String configFilename) :讀取使用Java的特性檔案編寫的配置檔案
  3. DOMConfigurator.configure ( String filename ) :讀取XML形式的配置檔案

4.1.3 插入記錄資訊

當上兩個必要步驟執行完畢,您就可以輕鬆地使用不同優先順序別的日誌記錄語句插入到您想記錄日誌的任何地方,其語法如下:
  1. Logger.debug ( Object message ) ;
  2. Logger.info ( Object message ) ;
  3. Logger.warn ( Object message ) ;
  4. Logger.error ( Object message ) ;

4.2 入門使用

不詳細展開描述,詳見參考:

4.3 Web使用

web應用的log4j使用基本上都採用:新建一個servlet,這個servlet在init函式中為log4j執行配置,一般就是讀入配置檔案。

1、在web.xml中配置servlet,同時設定load-on-startup為0。配置檔案位置在web.xml中配置一個param即可,路徑一般是相對於web的root目錄。
  1. <servlet>
  2. <servlet-name>InitLog4jServlet</servlet-name>
  3. <servlet-class>indiv.dulk.wechat.init.InitLog4jServlet</servlet-class>
  4. <init-param>
  5. <param-name>propertiesLocation</param-name>
  6. <param-value>/WEB-INF/classes/log4j.properties</param-value>
  7. </init-param>
  8. <load-on-startup>0</load-on-startup>
  9. </servlet>

2、這個servlet配置log4j就是讀出配置檔案,然後呼叫configure函式。這裡有兩個問題:一、需要知道檔案在哪裡;二、需要正確的檔案型別(檔案型別一般有兩種,一個是Java的property檔案,另一種是xml檔案)
  1. public class InitLog4jServlet extends HttpServlet{
  2. /**
  3. * Servlet初始化的執行方法,用以載入log4j配置檔案
  4. *
  5. * @throws ServletException
  6. */
  7. @Override
  8. public void init() throws ServletException {
  9. System.out.println("*** Log4jInitServlet正在初始化log4j日誌設定資訊 ***");
  10. String log4jLocation = getInitParameter("propertiesLocation");
  11. if (log4jLocation == null) {
  12. System.err.println("*** 沒有找到log4j的properties配置檔案,使用預設log4j環境初始化 ***");
  13. BasicConfigurator.configure();
  14. } else {
  15. String webAppPath = getServletContext().getRealPath("/");
  16. String log4jRealLocation = webAppPath + log4jLocation;
  17. File log4jFile = new File(log4jRealLocation);
  18. if (log4jFile.exists()) {
  19. System.out.println("*** 使用" + log4jRealLocation + "進行log4j環境初始化 ***");
  20. PropertyConfigurator.configure(log4jRealLocation);
  21. } else {
  22. System.err.println("*** " + log4jRealLocation + "檔案未找到,使用預設log4j環境初始化 ***");
  23. BasicConfigurator.configure();
  24. }
  25. }
  26. }
  27. }

3、完成設定後在其他類中就可以獲取Logger來進行日誌列印
  1. public class InitWechatServlet extends HttpServlet{
  2. private static Logger log = Logger.getLogger(InitWechatServlet.class);
  3. /**
  4. * 重新整理的間隔時間(單位:毫秒),預設為1h,可以在web.xml自定義配置
  5. */
  6. private long period = 3600000;
  7. /**
  8. * 時間間隔時需要執行的任務內容
  9. */
  10. private TimerTask timerTask = new TimerTask() {
  11. @Override
  12. public void run() {
  13. //獲取最新的access_token並設定到WeChatAPI類中的靜態屬性中去
  14. WechatAPI.setAccessToken(WechatUtil.getNewAccessToken());
  15. log.info("微信accessToken重新整理 " + WechatAPI.getAccessToken());
  16. }
  17. };
  18. }



5、參考連結

相關文章