動態配置log4j

1 配置外部配置文件來配置的基本步驟
1.1 一個運用配置文件的實例
Log4j之因此能成功的緣由之一是它的靈活性。但若是隻是簡單的調用BasicConfigurator.configure()來進行配置工做,那麼全部的配置都是在函數中寫死的,之後修改配置就要修改原代碼,這就不能體現出log4j的靈活性了,因此基本上不會經過BasicConfigurator.configure()來進行配置工做的。
爲了增長軟件的靈活性,最經常使用的作法就是使用配置文件,如web.xml之於J2EE,struts-config.xml之於struts同樣,log4j也提供了讓咱們把配置信息從程序轉移到配置文件中的方法。Log4j提供了兩種方式的配置文件:XML文件和Java的property配置文件。經過把配置信息轉移到外部文件中,當咱們要修改配置信息時,就能夠直接修改配置文件而不用去修改代碼了,下面,咱們就來完成一個經過配置文件來實現log4j的實例。
例2-a:
package TestLog4j;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority; public class TestLog4j
{
static Logger logger = Logger.getLogger(TestLog4j.class.getName());
public TestLog4j(){}
 
public static void main(String[] args)
{
//經過BasicConfigurator類來初始化
//BasicConfigurator.configure();
//(1)經過配置文件來初始化
PropertyConfigurator.configure("F:\\nepalon\\log4j.properties");
 
logger.debug("Start of the main() in TestLog4j"); //代碼(2)
logger.info("Just testing a log message with priority set to INFO");
logger.warn("Just testing a log message with priority set to WARN");
logger.error("Just testing a log message with priority set to ERROR");
logger.fatal("Just testing a log message with priority set to FATAL");
logger.log(Priority.WARN, "Testing a log message use a alternate form");
logger.debug(TestLog4j.class.getName()); //代碼(2)
}
}
在這個例子中,咱們用PropertyConfigurator.configure("F:\\nepalon\\log4j.properties")代替BasicConfigurator.configure()進行配置。PropertyConfigurator.configure()函數的參數能夠是一個properties文件所在路徑的String對象,能夠是一個properties文件所在路徑的URL對象,也能夠是一個properties對象。經過PropertyConfigurator.configure()能夠經過指定的properties文件來配置信息。若是要用XML文件進行信息配置,能夠在代碼中調用DOMConfigurator()函數來進行配置工做。在這裏,咱們只以properties文件來完成例子。接着,咱們來看一下log4j.properties文件中都有些什麼東西:
例2-b:
log4j.rootLogger = DEBUG, A1
log4j.appender.A1 = org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout = org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c %x - %m%n
運行這個實例,運行結果爲
0 [main] DEBUG TestLog4j.TestLog4j - Start of the main() in TestLog4j
20 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
20 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
20 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
20 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
180 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
180 [main] DEBUG TestLog4j.TestLog4j - TestLog4j.TestLog4j
下面,咱們分析一下這個配置文件。
1) 因爲每個Logger對旬都有一個級別,文件的第一行就是定義了一個Logger及其級別。在這裏定義了一個根記錄器(root logger),這涉及到記錄器的層次問題,在些暫時不深刻討論,在後面的章節再進行討論。
2) 第二行定義了一個名爲A1的輸出流,這個流就是控制檯,因此經過Logger對象打印的信息會在控制檯輸出。
3) 第三行定義了打印信息的佈局。在這裏咱們用PatternLayout做爲此記錄器的佈局,PatternLayout容許你以靈活的格式來打印信息。
4) 第四行指定的打印信息的具體格式,從結果可知,這個實例的打印格式爲:當前打印語句所使用的時間 [日誌所在的線程] 打印的級別 當前日誌所在的類的全名 日誌信息。
如今咱們來修改一下這個記錄器的級別,把第一行的DEBUG改成INFO,再運行程序,結果將變爲:
0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
10 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
10 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
10 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
10 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
因爲這個Logger的級別變爲INFO,而代碼(2)是調用debug()函數來輸出日誌信息時只能當記錄器級別爲DEBUG時才輸出信息,因此代碼(2)將不輸出信息。
1.2 實例原理
1.2.1 初始化配置信息
若是要經過JAVA的properties文件來配置信息,那麼在代碼中就要經過PropertyConfigurator.configure()函數從properties文件中加載配置信息,這個函數有三種參數形式:一個properties文件所在路徑的String對象,能夠是一個properties文件所在路徑的URL對象,也能夠是一個properties對象。若是要用XML文件來配置信息,則可用類型的
DOMConfigurator()函數來從一個XML文件中加載配置信息。
1.2.2 輸出端Appender
在上面的例子中,咱們都是簡單的把日誌信息輸出到控制檯中。其實在log4j中還能夠把日誌信息輸出到其它的輸出端,對於同一個日誌信息,咱們還可讓它同時輸出到多個輸出端中,如同時在控制檯和文件中進行打印。一個輸出端就是一個appender。要在配置文件中定義一個appender有三步:
1) 在定義一個記錄器的同時定義出該記錄器的輸出端appender。在例2的配置文件的第一句log4j.rootLogger = DEBUG, A1中,咱們定義了一個根記錄器,它的級別爲DEBUG,它有一個appender名爲A1。定義根記錄器的格式爲log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN。同一個記錄器可有多個輸出端。
2) 定義appender的輸出目的地。定義一個appender的輸出目的地的格式爲log4j.appender.appenderName = fully.qualified.name.of.appender.class。log4j提供瞭如下幾種經常使用的輸出目的地:
? org.apache.log4j.ConsoleAppender,將日誌信息輸出到控制檯
? org.apache.log4j.FileAppender,將日誌信息輸出到一個文件
? org.apache.log4j.DailyRollingFileAppender,將日誌信息輸出到一個,而且天天輸出到一個新的日誌文件
? org.apache.log4j.RollingFileAppender,將日誌信息輸出到一個文件,經過指定文件的的尺寸,當文件大小到達指定尺寸的時候會自動把文件更名,如名爲example.log的文件會更名爲example.log.1,同時產生一個新的example.log文件。若是新的文件再次達到指定尺寸,又會自動把文件更名爲example.log.2,同時產生一個example.log文件。依此類推,直到example.log. MaxBackupIndex,MaxBackupIndex的值可在配置文件中定義。
? org.apache.log4j.WriterAppender,將日誌信息以流格式發送到任意指定的地方。
? org.apache.log4j.jdbc.JDBCAppender,經過JDBC把日誌信息輸出到數據庫中。
在例2中,log4j.appender.A1 = org.apache.log4j.ConsoleAppender定義了名爲A1的appender的輸出目的地爲控制檯,因此日誌信息將輸出到控制檯。
3) 定義與所選的輸出目的地相關的參數,定義格式爲:
log4j.appender.appenderName.optionName1 = value1
……
log4j.appender.appenderName.optionNameN = valueN
其中一個最經常使用的參數layout將在下面介紹。
1.2.3 輸出格式(佈局)layout
經過appender能夠控制輸出的目的地,而若是要控制輸出的格式,就可經過log4j的layout組件來實現。經過配置文件定義一個appender的輸出格式,也一般須要兩個步驟:
1) 定義appender的佈局模式。定義一個appender的佈局模式的格式爲log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class。Log4j提供的佈局模式有如下幾種:
? org.apache.log4j.HTMLLayout,以HTML表格形式佈局
? org.apache.log4j.PatternLayout,能夠靈活地指定佈局模式
? org.apache.log4j.SimpleLayout,包含日誌信息的級別和信息字符串
在例2 中log4j.appender.A1.layout = org.apache.log4j.PatternLayout定義了名爲A1的appender的佈局模式爲PatternLayout。
2) 定義與所選的佈局模式相關的設置信息,定義格式爲:
log4j.appender.appenderName.layout.optionName1 = value1
……
log4j.appender.appenderName.layout.optionNameN = valueN
選擇了不一樣的佈局模式可能會有不一樣的設置信息。實例2所選的佈局模式PatternLayout的一個PatternLayout爲ConversionPattern ,經過定義這個PatternLayout的值,咱們能夠指定輸出信息的輸出格式。在例2的配置文件中的定義以下log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c %x - %m%n。在下面,咱們將介紹佈局模式PatternLayout的參數ConversionPattern的各個值表明的含義。
1.2.4 ConversionPattern參數的格式含義
格式名 含義
%c 輸出日誌信息所屬的類的全名
%d 輸出日誌時間點的日期或時間,默認格式爲ISO8601,也能夠在其後指定格式,好比:%d{yyy-MM-dd HH:mm:ss },輸出相似:2002-10-18- 22:10:28
%f 輸出日誌信息所屬的類的類名
%l 輸出日誌事件的發生位置,即輸出日誌信息的語句處於它所在的類的第幾行
%m 輸出代碼中指定的信息,如log(message)中的message
%n 輸出一個回車換行符,Windows平臺爲 \r\n ,Unix平臺爲 \n
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL。若是是調用debug()輸出的,則爲DEBUG,依此類推
%r 輸出自應用啓動到輸出該日誌信息所耗費的毫秒數
%t 輸出產生該日誌事件的線程名
1.3 定義多個輸出目的地的實例
從上面的實例原理中咱們已經知道,同一個日誌信息能夠同時輸出到多個輸出目的地,在這個例子中,咱們將實現一個把日誌信息同時輸出到控制器、一個文件中的實例和數據庫中。這個實例的Java代碼咱們沿用例2中的代碼,咱們只需修改配置文件便可。這也體現了log4j的靈活性。
例3-a:
create table log4j(
logID int primary key identity,
message varchar(1024),
priority varchar(10),
milliseconds int,
category varchar(256),
thread varchar(100),
NDC varchar(256),
createDate datetime,
location varchar(256),
caller varchar(100),
method varchar(100),
filename varchar(100),
line int
)
例3-b:
#1 定義了兩個輸出端
log4j.rootLogger = INFO, A1, A2,A3
 
#2 定義A1輸出到控制器
log4j.appender.A1 = org.apache.log4j.ConsoleAppender
#3 定義A1的佈局模式爲PatternLayout
log4j.appender.A1.layout = org.apache.log4j.PatternLayout
#4 定義A1的輸出格式
log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c - %m%n
 
#5 定義A2輸出到文件
log4j.appender.A2 = org.apache.log4j.RollingFileAppender
#6 定義A2要輸出到哪個文件
log4j.appender.A2.File = F:\\nepalon\\classes\\example3.log
#7 定義A2的輸出文件的最大長度
log4j.appender.A2.MaxFileSize = 1KB
#8 定義A2的備份文件數
log4j.appender.A2.MaxBackupIndex = 3
#9 定義A2的佈局模式爲PatternLayout
log4j.appender.A2.layout = org.apache.log4j.PatternLayout
#10 定義A2的輸出格式
log4j.appender.A2.layout.ConversionPattern = %d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n
 
#11區 定義A3輸出到數據庫
log4j.appender.A3 = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.A3.BufferSize = 40
log4j.appender.A3.Driver = com.microsoft.jdbc.sqlserver.SQLServerDriver
log4j.appender.A3.URL = jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=nepalon
log4j.appender.A3.User = sa
log4j.appender.A3.Password =
log4j.appender.A3.layout = org.apache.log4j.PatternLayout
log4j.appender.A3.layout.ConversionPattern = INSERT INTO log4j (createDate, thread, priority, category, message) values(getdate(), '%t', '%-5p', '%c', '%m')
配置文件中的六、七、8行顯示了輸出端爲RollingFileAppender的特有參數及其運用的方法。11區顯示了輸出端爲JDBCAppender的特有參數及其運用方法。在這着重講解一下六、七、8行的做用。6行指定日誌信息輸出到哪一個文件,7行指定日誌文件的最大長度,最後要詳細介紹8行。第8行的參數是設置備份文件的個數的參數,在這裏咱們設置爲3,表示最多有3個備份文件,具體做用爲:
1) 當example3.log文件的大小超過K時,就把文件更名爲example3.log.1,同時生成一個新的example3.log文件
2) 當example3.log文件的大小再次超過1K,又把文件更名爲example3.log.1。但因爲此時example3.log.1已存在,則先把example3.log.1改名爲example3.log.2,再把example3.log文件更名爲example3.log.1
3) 同理,當example3.log文件的大小再次超過1K,先把example3.log.2文件改名爲example3.log.3,把example3.log.1文件改名爲example3.log.2,再把example3.log文件更名爲example3.log.1
4) 當example3.log文件的大小再次超過1K,先把example3.log.2文件改名爲example3.log.3,舊的example3.log.3文件將被覆蓋;把example3.log.1文件改名爲example3.log.2,舊的example3.log.2文件被覆蓋;最後把example3.log文件更名爲example3.log.1並覆蓋掉舊的example3.log.1文件。
運行結果將分爲兩部分
在控制器中:
0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
11 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
21 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR 21 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
21 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form
在文件example3.log中:
2003-12-18 04:23:02:INFO main TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
2003-12-18 04:23:02:ERROR main TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
2003-12-18 04:23:02:FATAL main TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Testing a log message use a alternate form
1.4 配置log4j的總結
這個教程到這裏,關於配置log4j的配置文件的基本原理已經講完了,並且經過例3咱們已經能夠完成基本的日誌工做了。如今,咱們就作一個總結。配置一個配置文件的基本步驟以下:
1) 定義一個Logger。在定義Logger時指定該Logger的級別級其輸出目的地。定義Logger的格式爲
log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN。
2) 定義appender的輸出目的地。定義一個appender的輸出目的地的格式爲
log4j.appender.appenderName = fully.qualified.name.of.appender.class。
log4j提供的輸出端有ConsoleAppender、FileAppender 、DailyRollingFileAppender、RollingFileAppender和WriterAppender。
3) 定義appender的除佈局模式外的其它相關參數,如例3中第六、七、8定義了A2的相關參數。定義格式爲
log4j.appender.appenderName.optionName1 = value1
……
log4j.appender.appenderName.optionNameN = valueN
若是除了佈局模式外不須要定義別的參數,可跳過這一步(如例3中的A1)。
4) 定義appender的佈局模式。定義一個appender的佈局模式的格式爲
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class。
佈局模式其實也是步驟3)中的一個部分,只是佈局模式參數是每個appender必須定義的參數。Log4j提供的佈局模式有HTMLLayout、PatternLayout和SimpleLayout。
5) 定義與所選的佈局模式相關的設置信息,定義格式爲
og4j.appender.appenderName.layout.optionName1 = value1
……
log4j.appender.appenderName.layout.optionNameN = valueN
2 記錄器的層次Logger hierarchy
2.1 何爲記錄器的層次hierarchy
首先,咱們先看一下何爲層次,以咱們最熟悉的繼承爲例,下面是一張類圖
 
在這個繼承體系中,類B是類C的父類,類A是類C的祖先類,類D是類C的子類。這些類之間就構成一種層次關係。在這些具備層次關係的類中,子類均可繼承它的父類的特徵,如類B的對象能調用類A中的非private實例變量和函數;而類C因爲繼承自類B,因此類B的對象能夠同時調用類A和類B中的非private實例變量和函數。
在log4j中,處於不一樣層次中的Logger也具備象類這樣的繼承關係。
2.2 記錄器的層次
若是一個應用中包含了上千個類,那麼也幾乎須要上千個Logger實例。如何對這上千個Logger實例進行方便地配置,就是一個很重要的問題。Log4J採用了一種樹狀的繼承層次巧妙地解決了這個問題。在Log4J中Logger是具備層次關係的。它有一個共同的根,位於最上層,其它Logger遵循相似包的層次。下面咱們將進行介紹。
2.2.1 根記錄器root logger
就象一個Java中的Object類同樣,log4j中的logger層次中有一個稱之爲根記錄器的記錄器,其它全部的記錄器都繼承自這個根記錄器。根記錄器有兩個特徵:
1) 根記錄器老是存在。就像Java中的Object類同樣,由於用log4j輸出日誌信息是經過記錄器來實現的,因此只要你應用了log4j,根記錄器就確定存在的。
2) 根記錄器沒有名稱,因此不能經過名稱來取得根記錄器。但在Logger類中提供了getRootLogger()的方法來取得根記錄器。
2.2.2 記錄器的層次
Logger遵循相似包的層次。如
static Logger rootLog = Logger.getRootLogger();
static Logger log1 = Logger.getLogger("test4j");
static Logger log2 = Logger.getLogger("test4j.test4j2");
static Logger log3 = Logger.getLogger("test4j.test4j2.test4j2");
那麼rootLog是log2的祖先子記錄器,log1是log2的父子記錄器,log3是log2的子記錄器。記錄器象Java中的類繼承同樣,子記錄器能夠繼承父記錄器的設置信息,也能夠能夠覆寫相應的信息。
首先先看一下記錄器層次中的繼承有什麼用處。假設程序中的每一個包都具備一些基本的日誌信息,而包中的不一樣包可能會有些額外的日誌信息要輸出,這種狀況就能夠象處理Java中的類同樣,運用Logger中的層次關係來達到目的。假設有個名爲A的包,我包下的全部類都要把日誌信息輸出到控制檯中;A.B包除了輸出到控制檯外還要輸出到文件中;A.C包除了輸出到控制檯中還要輸出到HTML文檔中。這樣咱們就能夠經過定義一個父記錄器A,它負責把日誌信息輸出到控制檯中;定義一個A的子記錄器A.B,它負責把日誌信息輸出到文件中;定義一個A的子記錄器A.C,它負責把日誌信息輸出到HTML文檔中。
記錄器遵循的是相似包的層次,這樣作爲咱們帶來了大大的方便。Logger類中的getLogger()方法能夠取得Logger對象,這個方法有三種參數形式String、Class和URL,其實不管是用哪種,最終都是經過記錄器的名字來取得記錄器對象的。若是要取得一個名爲A.B的記錄器對象,咱們能夠Logger.getLogger( A.B )。但從上面的例子中,咱們都是經過Logger.getLogger(TestLog4j.class.getName())這種方法來取得記錄器對象。這是爲何呢?如今咱們假設A.B的包下有一個類BClass,那麼咱們調用BClass.class.getName()獲得的是這個類的全名A.B.BClass。因此當調用Logger.getLogger(BClass.class.getName())時,最理想的狀況是返回名爲A.B.BClass的記錄器對象。可是若是不存在名爲A.B.BClass的記錄器時它會怎樣呢?其實經過Logger類的getLogger方法取得記錄器時存在下面兩種狀況:
1) 若是存在與所要找的名字徹底相同的記錄器,則返回相應的記錄器對象。
當調用Logger.getLogger(BClass.class.getName())時,若是定義了名爲A.B.BClass的記錄器,它就返回該記錄器的對象。
2) 但若是找不到,它會嘗試返回在記錄器層次中與所要找的記錄器最接近的記錄器對象。
當調用Logger.getLogger(BClass.class.getName())時,若是沒有定義了名爲A.B.BClass的記錄器,那會嘗試返回名爲A.B的記錄器的對象;若是又沒有定義名爲A.B的記錄器,它會嘗試返回名爲A的記錄器的對象;若是也沒定義名爲A的記錄器,它就會返回根記錄器的對象,而根記錄器是必須存在的,因此你總能獲得一個記錄器對象。
好了,如今咱們回到前面的問題,咱們爲何總要經過Logger.getLogger(BClass.class.getName())這種以類全名做爲參數來取得記錄器對象呢?其實這是爲了管理方便。由於咱們在定義設計Logger時也遵循相似包的規則,使設計器的名稱與程序中的類包對應。如上面的假設中咱們的程序中有A包,A包下有B包和C包,B包下又有類BClass,那麼咱們就可以使設計器的名爲A、A.B、A.C、A.B.BClass,以此類推。那麼當咱們經過類命名來取得設計器對象時,總能取到與所要的設計器最接近的設計器對象。
2.3 如何應用記錄器的層次
2.3.1 若是定義及獲取不一樣層次的記錄器
任何一個記錄器的使用都有兩個步驟:
1) 在配置文件中定義相應的記錄器。
在配置文件中定義記錄器的格式有兩種
? 定義根記錄器的格式爲
log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN
? 定義一個非根記錄器的格式爲
log4j.logger.loggerName1 = [ level ], appendName1,…appendNameN
……
log4j.logger.loggerNameM = [ level ], appendName1, …appendNameN
咱們能夠定義任意個非根記錄器。
2) 在代碼中調用Logger類的取得記錄器方法取得相應的記錄器對象。
要取得根記錄器對象可經過Logger.getRootLogger()函數,要取得非根記錄器可經過Logger.getLogger()函數。
理論知道就講到這裏,紙上得來終覺淺,下面,咱們來小小演練一下。
例4-a:
package TestLog4j;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority;
import TestLog4j.TestLog4j2.TestLog4j2;
 
public class TestLog4j
{
static Logger logger = Logger.getLogger(TestLog4j.class.getName()); //(2)
public TestLog4j(){}
 
public static void main(String[] args)
{
//同時輸出到控制檯和一個文件的實例並實現了Logger的繼承
PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties");
 
logger.debug("Start of the main() in TestLog4j");
logger.info("Just testing a log message with priority set to INFO");
logger.warn("Just testing a log message with priority set to WARN");
logger.error("Just testing a log message with priority set to ERROR");
logger.fatal("Just testing a log message with priority set to FATAL");
logger.log(Priority.WARN, "Testing a log message use a alternate form");
logger.debug(TestLog4j.class.getName());
TestLog4j2 testLog4j2 = new TestLog4j2(); //(1)
testLog4j2.testLog();
}
}
在類TestLog4j中咱們調用了另外一個類TestLog4j2,下面看一下類TestLog4j2的代碼。
例4-b:
package TestLog4j.TestLog4j2;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Priority;
 
public class TestLog4j2
{
static Logger logger = Logger.getLogger(TestLog4j2.class.getName()); //(1)
public TestLog4j2(){}
 
public void testLog()
{
//同時輸出到控制檯和一個文件的實例
PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties");
logger.debug("2Start of the main()");
logger.info("2Just testing a log message with priority set to INFO");
logger.warn("2Just testing a log message with priority set to WARN");
logger.error("2Just testing a log message with priority set to ERROR");
logger.fatal("2Just testing a log message with priority set to FATAL");
logger.log(Priority.DEBUG, "Testing a log message use a alternate form");
logger.debug("2End of the main()");
}
}
最後咱們來看一下配置文件。
例4-c:
log4j2.properties文件內容
#1區
#### Use two appenders, one to log to console, another to log to a file
log4j.rootLogger = debug, stdout
 
#2區
#Print only messages of priority WARN or higher for your category
log4j.logger.TestLog4j= , R
log4j.logger.TestLog4j.TestLog4j2=WARN
 
#3區
#### First appender writes to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
 
#4區
#### Second appender writes to a file
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=F:\\nepalon\\classes\\TestLog4j\\example.log
 
# Control the maximum log file size
log4j.appender.R.MaxFileSize=100KB
# Archive log files (one backup file here)
log4j.appender.R.MaxBackupIndex=1
 
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n
先看一下運行結果。
在控制檯中的結果爲:
DEBUG [main] (?:?) - Start of the main() in TestLog4j
INFO [main] (?:?) - Just testing a log message with priority set to INFO
WARN [main] (?:?) - Just testing a log message with priority set to WARN
ERROR [main] (?:?) - Just testing a log message with priority set to ERROR
FATAL [main] (?:?) - Just testing a log message with priority set to FATAL
WARN [main] (?:?) - Testing a log message use a alternate form
DEBUG [main] (?:?) - TestLog4j.TestLog4j
WARN [main] (?:?) - 2Just testing a log message with priority set to WARN
ERROR [main] (?:?) - 2Just testing a log message with priority set to ERROR
FATAL [main] (?:?) - 2Just testing a log message with priority set to FATAL
輸出文件的結果爲:
2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - Start of the main() in TestLog4j
2003-12-19 04:19:44:INFO main TestLog4j.TestLog4j - Just testing a log message with priority set to INFO
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Just testing a log message with priority set to WARN
2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j - Just testing a log message with priority set to ERROR
2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j - Just testing a log message with priority set to FATAL
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Testing a log message use a alternate form
2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - TestLog4j.TestLog4j
2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to WARN
2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to ERROR
2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testing a log message with priority set to FATAL
 
首先,先來看一下配置文件都有些什麼東西。
1) 在1區中定義了一個根記錄器。這個根記錄器具備DEBUG級別並有一個名稱爲stdout的輸出端appender。
2) 2區中的內容是這一節的重點,也是應用到記錄器層次的地方,但其實也只有兩句,充分體現了log4j的簡單性。在這裏,咱們定義了兩個名稱分別爲TestLog4j和TestLog4j.TestLog4j2設計器。
? 在定義TestLog4j記錄器時沒有指定級別,因此它的級別繼承自它的父記錄器,即要記錄器,因此它的級別也爲DEBUG。在定義TestLog4j記錄器時又定義了一個名稱爲R的輸出端,因此它的輸出端有兩個,一個從根記錄器繼承而來的名爲stdout的輸出端,另外一個爲在此定義的名爲R的輸出端。在此須要注意的是,在定義記錄器時必須先定義記錄器的級別,而後纔是記錄器的輸出端。若是隻想定義輸出端而不定義級別,則雖然級別能夠爲空,但逗號分隔符不能省略。如定義TestLog4j記錄器的作法。
? 在定義TestLog4j.TestLog4j2記錄器時又指定了它的級別,因爲一個記錄器的級別只能有一個,因此新指定的級別將覆寫掉它的父記錄器的級別(這就象Java中的多態)。咱們沒有定義TestLog4j.TestLog4j2記錄器的輸出端,因此它的輸出端將從它的父記錄器中繼承而來。它的父記錄器爲estLog4j記錄器,因此它和estLog4j記錄器同樣具備兩個名稱分別爲stdout和R的輸出端。
3) 剩下的3區和4區分別設置了兩個輸出端的參數值。
接下來,回到咱們的代碼,看一下是如何取得記錄器,在取記錄器時又發生了什麼。
1) 例4-a中的代碼(2)中,語句Logger.getLogger()中的參數TestLog4j.class.getName()的值爲TestLog4j. TestLog4j,因此此語句的結果是取得一個名爲TestLog4j. TestLog4j的記錄器的對象。但在配置文件中並無定義這樣的記錄器,因此最終將返回與所需的名稱TestLog4j. TestLog4j最接近的記錄器對象,即名爲TestLog4j的記錄器的對象。
2) 例4-b中的代碼(1)的原理與例4-a中的代碼(2)類似,指望取得的是名爲TestLog4j.TestLog4j2. TestLog4j2的記錄器對象,但最終返回的是TestLog4j.TestLog4j2記錄器的對象。
三 log4j與J2EE的結合
到目前爲止,這篇文章講的都是如何在application中應用log4j,而Java如今的應用主流是J2EE和J2ME。如今,咱們來看一下要如何在J2EE開發中應用log4j。其實在Web application中應用log4j也很簡單,與在application中應用log4j不一樣之處就是要在全部應用log4j的代碼以前對log4j進行初始化。因此,咱們在web application中就要把log4j的初始化工做獨立出來,把它放在Servlet中。下面,咱們看一個例子。
例5-a:
進行初始化的Servlet:
import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
* log4j.jar的初始化類,參考web.xml
*/
public class Log4jInit extends HttpServlet
{
public void init()
{
//經過web.xml來動態取得配置文件
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");
 
// 若是沒有給出相應的配置文件,則不進行初始化
if(file != null)
{
PropertyConfigurator.configure(prefix+file); //(1)
}
}
 
public void doGet(HttpServletRequest req, HttpServletResponse res)
{}
}
下面來看一下這個Servlet在web.xml中的定義。
例5-b:
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>TestLog4j.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-init-file</param-name>
<param-value>sort.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
由於log4j的初始化要在全部的log4j調用以前完成,因此在web.xml文件中,咱們必定要把對應的Servlet定義的load-on-startup應設爲1,以便在Web容器啓動時即裝入該Servlet。
完成了這兩個步驟這後,咱們就能夠象在application開發中同樣在web application任何地方應用log4j了。下面是在javabean中的應用的一個例子。
例5-c:
import org.apache.log4j.Logger;
 
public class InfoForm
{
static Logger logger = Logger.getLogger(InfoForm.class);
 
protected String title;
protected String content;
 
public InfoForm() {}
 
public void setTitle(Object value)
{
logger.debug("nepalon:title = " + title);
title = value;
}
 
public String getTitle()
{
logger.debug("nepalon:title = " + title);
return title;
}
 
public void setContent(String value)
{
content = value;
logger.debug("nepalon: content() = " + content);
}
 
public String getContent()
{
logger.debug("nepalon: content = \n" + content);
return content;
}
}
相關文章
相關標籤/搜索