1. 程式人生 > >JAVA 開發平臺的技術和框架(五)日誌管理 :common-logging slf4j log4j logBack

JAVA 開發平臺的技術和框架(五)日誌管理 :common-logging slf4j log4j logBack

common-logging

common-logging是apache提供的一個通用的日誌介面。使用者可以自由選擇第三方的日誌元件作為具體實現,像log4j,或者jdk自帶的logging, common-logging會通過動態查詢的機制,在程式執行時自動找出真正使用的日誌庫。當然,common-logging內部有一個Simple logger的簡單實現,但是功能很弱。所以使用common-logging,通常都是配合著log4j來使用。使用它的好處就是,程式碼依賴是common-logging而非log4j, 避免了和具體的日誌方案直接耦合,在有必要時,可以更改日誌實現的第三方庫。

使用common-logging的常見程式碼:

<span style="font-size:12px;">import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class A {
	private static Log logger = LogFactory.getLog(this.getClass());
}</span>

動態查詢原理:Log 是一個介面宣告。LogFactory 的內部會去裝載具體的日誌系統,並獲得實現該Log 介面的實現類。LogFactory 內部裝載日誌系統的流程如下:

  1. 首先,尋找org.apache.commons.logging.LogFactory 屬性配置。
  2. 否則,利用JDK1.3 開始提供的service 發現機制,會掃描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory檔案,若找到則裝載裡面的配置,使用裡面的配置。
  3. 否則,從Classpath 裡尋找commons-logging.properties ,找到則根據裡面的配置載入。
  4. 否則,使用預設的配置:如果能找到Log4j 則預設使用log4j 實現,如果沒有則使用JDK14Logger 實現,再沒有則使用commons-logging 內部提供的SimpleLog 實現。

從上述載入流程來看,只要引入了log4j 並在classpath 配置了log4j.xml ,則commons-logging 就會使log4j 使用正常,而程式碼裡不需要依賴任何log4j 的程式碼。

slf4j

以下摘自百度百科:

SLF4J,即簡單日誌門面(Simple Logging Facade for Java),不是具體的日誌解決方案,它只服務於各種各樣的日誌系統。按照官方的說法,SLF4J是一個用於日誌系統的簡單Facade,允許終端使用者在部署其應用時使用其所希望的日誌系統。 實際上,SLF4J所提供的核心API是一些介面以及一個LoggerFactory的工廠類。從某種程度上,SLF4J有點類似JDBC,不過比JDBC更簡單,在JDBC中,你需要指定驅動程式,而在使用SLF4J的時候,不需要在程式碼中或配置檔案中指定你打算使用那個具體的日誌系統。如同使用JDBC基本不用考慮具體資料庫一樣,SLF4J提供了統一的記錄日誌的介面,只要按照其提供的方法記錄即可,最終日誌的格式、記錄級別、輸出方式等通過具體日誌系統的配置來實現,因此可以在應用中靈活切換日誌系統。

使用slf4j

slf4j靜態繫結原理:SLF4J 會在編譯時會繫結import org.slf4j.impl.StaticLoggerBinder; 該類裡面實現對具體日誌方案的繫結接入。任何一種基於slf4j 的實現都要有一個這個類。如:org.slf4j.slf4j-log4j12-1.5.6: 提供對 log4j 的一種適配實現。注意:如果有任意兩個實現slf4j 的包同時出現,那麼就可能出現問題。

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

public class A {
	private static final Logger log = LoggerFactory.getLogger(A.class);}

slf4j 與 common-logging 比較

common-logging通過動態查詢的機制,在程式執行時自動找出真正使用的日誌庫。由於它使用了ClassLoader尋找和載入底層的日誌庫, 導致了象OSGI這樣的框架無法正常工作,因為OSGI的不同的外掛使用自己的ClassLoader。 OSGI的這種機制保證了外掛互相獨立,然而卻使Apache Common-Logging無法工作。


slf4j在編譯時靜態繫結真正的Log庫,因此可以再OSGI中使用。另外,SLF4J 支援引數化的log字串,避免了之前為了減少字串拼接的效能損耗而不得不寫的if(logger.isDebugEnable()),現在你可以直接寫:logger.debug(“current user is: {}”, user)。拼裝訊息被推遲到了它能夠確定是不是要顯示這條訊息的時候,但是獲取引數的代價並沒有倖免。

LOG4J

Log4j是Apache的一個開放原始碼專案,通過使用Log4j,我們可以控制日誌資訊輸送的目的地是控制檯、檔案、GUI元件,甚至是套介面伺服器、NT的事件記錄器、UNIX Syslog守護程序等;我們也可以控制每一條日誌的輸出格式;通過定義每一條日誌資訊的級別,我們能夠更加細緻地控制日誌的生成過程。最令人感興趣的就是,這些可以通過一個配置檔案來靈活地進行配置,而不需要修改應用的程式碼。

log4j使用:

1、加入log4j-1.2.8.jar(可以選擇log4j的更高版本)到lib下

2、在CLASSPATH下建立log4j.properties。配置內容

3、在要輸出日誌的類中加入相關語句:

定義屬性:static Logger logger = Logger.getLogger(LogDemo.class); //LogDemo為相關的類

LogBack

Logback是由log4j創始人設計的又一個開源日記元件。logback當前分成三個模組:logback-core,logback- classic和logback-access。logback-core是其它兩個模組的基礎模組。logback-classic是log4j的一個 改良版本。此外logback-classic完整實現SLF4J API使你可以很方便地更換成其它日記系統如log4j或JDK14 Logging。logback-access訪問模組與Servlet容器整合提供通過Http來訪問日記的功能。

Spring下 slf4j 和log4j配置

1、加入jar包:log4j-1.2.17.jar、slf4j-api-1.7.7.jar、slf4j-log4j12-1.7.7.jar

2、修改web.xml,把log4j加到專案中

<!-- Log4j配置 -->

 <context-param>

  <param-name>log4jConfigLocation</param-name>

  <param-value>classpath:log4j.properties</param-value>

 </context-param>

 <!-- 載入log4j配置檔案 -->

 <listener>

  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>

 </listener>

3、新建log4j.properties

示例的配置檔案 log4j.properties
 
log4j.debug=true   
log4j.rootLogger=DEBUG,D,E

log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/logs.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = DEBUG
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
#log4j.appender.E.layout.

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR
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

4、

經過上面的步驟後,log4j就配置好了,接下來是使用,在DemoController中使用,使用slf4j介面,代替log4j,這樣假如以後不用log4j了,用logback等其它日誌框架,只需修改配置檔案,不需要修改java程式碼

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

public class A {
	private static final Logger log = LoggerFactory.getLogger(A.class);}

log4j.properties的配置引數

1 基本格式如下:

#配置根Logger
log4j.rootLogger  =   [ level ]   ,  appenderName1 ,  appenderName2 ,  …

#配置日誌資訊輸出目的地Appender
log4j.appender.appenderName  =  fully.qualified.name.of.appender.class 
  log4j.appender.appenderName.option1  =  value1 
  … 
  log4j.appender.appenderName.optionN  =  valueN 

#配置日誌資訊的格式(佈局)
log4j.appender.appenderName.layout  =  fully.qualified.name.of.layout.class 
  log4j.appender.appenderName.layout.option1  =  value1 
  … 
  log4j.appender.appenderName.layout.optionN  =  valueN 
其中 [ level ]日誌輸出級別共有五級
FATAL      0  
ERROR      3  
WARN       4  
INFO       6  
DEBUG      7 

Appender 為日誌輸出目的地,Log4j提供的appender有以下幾種:

org.apache.log4j.ConsoleAppender(控制檯),
org.apache.log4j.FileAppender(檔案),
org.apache.log4j.DailyRollingFileAppender(每天產生一個日誌檔案),
org.apache.log4j.RollingFileAppender(檔案大小到達指定尺寸的時候產生一個新的檔案),
org.apache.log4j.WriterAppender(將日誌資訊以流格式傳送到任意指定的地方)

Layout:日誌輸出格式,Log4j提供的layout有以下幾種:

org.apache.log4j.HTMLLayout(以HTML表格形式佈局),
org.apache.log4j.PatternLayout(可以靈活地指定佈局模式),
org.apache.log4j.SimpleLayout(包含日誌資訊的級別和資訊字串),
org.apache.log4j.TTCCLayout(包含日誌產生的時間、執行緒、類別等等資訊)

列印引數: Log4J採用類似C語言中的printf函式的列印格式格式化日誌資訊,如下:

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

引數意義說明

輸出級別的種類
ERROR 為嚴重錯誤 主要是程式的錯誤
WARN 為一般警告,比如session丟失
INFO 為一般要顯示的資訊,比如登入登出
DEBUG 為程式的除錯資訊
配置日誌資訊輸出目的地
log4j.appender.appenderName=??
1.org.apache.log4j.ConsoleAppender(控制檯)
2.org.apache.log4j.FileAppender(檔案)
3.org.apache.log4j.DailyRollingFileAppender(每天產生一個日誌檔案)
4.org.apache.log4j.RollingFileAppender(檔案大小到達指定尺寸的時候產生一個新的檔案)
5.org.apache.log4j.WriterAppender(將日誌資訊以流格式傳送到任意指定的地方)
配置日誌資訊的格式
log4j.appender.appenderName.layout = ??
1.org.apache.log4j.HTMLLayout(以HTML表格形式佈局),
2.org.apache.log4j.PatternLayout(可以靈活地指定佈局模式),
3.org.apache.log4j.SimpleLayout(包含日誌資訊的級別和資訊字串),
4.org.apache.log4j.TTCCLayout(包含日誌產生的時間、執行緒、類別等等資訊)
ConsoleAppender選項
Threshold=DEBUG:指定日誌訊息的輸出最低層次。
ImmediateFlush=true:預設值是true,意謂著所有的訊息都會被立即輸出。
Target=System.err:預設情況下是:System.out,指定輸出控制檯
FileAppender 選項
Threshold=DEBUF:指定日誌訊息的輸出最低層次。
ImmediateFlush=true:預設值是true,意謂著所有的訊息都會被立即輸出。
File=mylog.txt:指定訊息輸出到mylog.txt檔案。
Append=false:預設值是true,即將訊息增加到指定檔案中,false指將訊息覆蓋指定的檔案內容。
RollingFileAppender 選項
Threshold=DEBUG:指定日誌訊息的輸出最低層次。
ImmediateFlush=true:預設值是true,意謂著所有的訊息都會被立即輸出。
File=mylog.txt:指定訊息輸出到mylog.txt檔案。
Append=false:預設值是true,即將訊息增加到指定檔案中,false指將訊息覆蓋指定的檔案內容。
MaxFileSize=100KB: 字尾可以是KB, MB 或者是 GB. 在日誌檔案到達該大小時,將會自動滾動,即將原來的內容移到mylog.log.1檔案。
MaxBackupIndex=2:指定可以產生的滾動檔案的最大數。
日誌資訊格式中幾個符號所代表的含義:
 -X號: X資訊輸出時左對齊;
 %p: 輸出日誌資訊優先順序,即DEBUG,INFO,WARN,ERROR,FATAL,
 %d: 輸出日誌時間點的日期或時間,預設格式為ISO8601,也可以在其後指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
 %r: 輸出自應用啟動到輸出該log資訊耗費的毫秒數
 %c: 輸出日誌資訊所屬的類目,通常就是所在類的全名
 %t: 輸出產生該日誌事件的執行緒名
 %l: 輸出日誌事件的發生位置,相當於%C.%M(%F:%L)的組合,包括類目名、發生的執行緒,以及在程式碼中的行數。舉例:Testlog4.main (TestLog4.java:10)
 %x: 輸出和當前執行緒相關聯的NDC(巢狀診斷環境),尤其用到像java servlets這樣的多客戶多執行緒的應用中。
 %%: 輸出一個"%"字元
 %F: 輸出日誌訊息產生時所在的檔名稱
 %L: 輸出程式碼中的行號
 %m: 輸出程式碼中指定的訊息,產生的日誌具體資訊
 %n: 輸出一個回車換行符,Windows平臺為"\r\n",Unix平臺為"\n"輸出日誌資訊換行

示例的配置檔案 log4j.properties

log4j.debug=true   
log4j.rootLogger=DEBUG,D,E

log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/logs.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = DEBUG
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
#log4j.appender.E.layout.

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR
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

載入配置檔案時 控制檯會顯示log4j解析配置檔案的過程 有錯誤會報錯

log4j: Parsing for [root] with value=[DEBUG,D,E].
log4j: Level token is [DEBUG].
log4j: Category root set to DEBUG
log4j: Parsing appender named "D".
log4j: Parsing layout options for "D".
log4j: Setting property [conversionPattern] to [%-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n].
log4j: End of parsing for "D".
log4j: Setting property [threshold] to [ERROR].
log4j: Setting property [append] to [true].
log4j: Setting property [file] to [logs/error.log].
log4j: setFile called: logs/error.log, true
log4j: setFile ended
log4j: Appender [D] to be rolled at midnight.
log4j: Parsed "D" options.
log4j: Parsing appender named "E".
log4j: Parsing layout options for "E".
log4j: Setting property [conversionPattern] to [%-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n].
log4j: End of parsing for "E".
log4j: Setting property [file] to [logs/logs.log].
log4j: Setting property [threshold] to [DEBUG].
log4j: Setting property [append] to [true].
log4j: setFile called: logs/logs.log, true
log4j: setFile ended
log4j: Appender [E] to be rolled at midnight.
log4j: Parsed "E" options.
log4j: Finished configuring.

slf4j與其他各種日誌元件的橋接

應用程式碼中使用slf4j介面,接入具體實現的方法


應用程式碼中使用別的日誌介面,轉成slf4j的方法