天天看點

Log4j簡明手冊(2/3)

4. 配置

插入日志請求到應用程式的代碼中需要大量的預先計劃和最終努力。觀察顯示大約4%的代碼是用來輸出的。

是以,大小适度的程式都被嵌入有成千個日志輸出語句。為了以無需手工的方式管理這些日志的輸出狀态,給日志輸出以編号和規範變得勢在必行。

Log4j在程式中有充分的可配置性。然而,用配置檔案配置Log4j具有更大的彈性。目前,它的配置檔案支援xml和java properties(key=value)檔案兩種格式。

讓我們以一個例子來示範它是如何做的。假定有一個用了Log4j的程式MyApp。

import com.foo.Bar;

// Import Log4j classes.

import org.apache.Log4j.Logger;

import org.apache.Log4j.BasicConfigurator;

public class MyApp {

// Define a static logger variable so that it references the

// Logger instance named "MyApp".

static Logger logger = Logger.getLogger(MyApp.class);

public static void main(String[] args) {

// Set up a simple configuration that logs on the console.

BasicConfigurator.configure();

logger.info("Entering application.");

Bar bar = new Bar();

bar.doIt();

logger.info("Exiting application.");

}

}

MyApp以引入Log4j的相關類開始,接着它定義了一個靜态logger變量,并給予值為"MyApp"類的全路徑名稱。

MYApp用了定義在包com.foo中的類Bar.

package com.foo;

import org.apache.Log4j.Logger;

public class Bar {

static Logger logger = Logger.getLogger(Bar.class);

public void doIt() {

logger.debug("Did it again!");

}

}

調用BasicConfigurator.configure()方法建立了一個相當簡單的Log4j的設定。它加入一

個ConsoleAppender到根logger。輸出将被采用了"%-4r [%t] %-5p %c %x - %m%n"模式

的PatternLayout所格式化。

注意,根logger預設被配置設定了Level.DEBUG的級别。

MyApp的輸出為:

0 [main] INFO MyApp - Entering application.

36 [main] DEBUG com.foo.Bar - Did it again!

51 [main] INFO MyApp - Exiting application.

随後的圖形描述了在調用BasicConfigurator.configure()方法後MyApp的對象圖。

一邊要提醒的是,Log4j的子logger隻連接配接到已經存在的它們的父代。特别的是,名為

com.foo.bar的logger是直接連接配接到根logger,而不是圍繞着沒用的com或com.foo

logger。這顯著的提高了程式性能并且減少的記憶體占用。

MyApp類配置Log4j是通過調用BasicConfigurator.configure 方法。其它的類僅僅

需要引入org.apache.Log4j.Logger 類,找到它們希望用的logger,并且用它就行。

以前的例子通常輸出同樣的日志資訊。幸運的是,修改MyApp是容易的,以便日志輸

出可以在運作時刻被控制。這裡是一個小小修改的版本。

import com.foo.Bar;

import org.apache.Log4j.Logger;

import org.apache.Log4j.PropertyConfigurator;

public class MyApp {

static Logger logger = Logger.getLogger(MyApp.class.getName());

public static void main(String[] args) {

// BasicConfigurator replaced with PropertyConfigurator.

PropertyConfigurator.configure(args[0]);

logger.info("Entering application.");

Bar bar = new Bar();

bar.doIt();

logger.info("Exiting application.");

}

}

修改後的 MyApp通知程式調用PropertyConfigurator()方法解析一個配置檔案,并且根

據這個配置檔案來設定日志。

這裡是一個配置檔案的例子,它将産生同以前BasicConfigurator 基本例子一樣

的輸出結果。

# Set root logger level to DEBUG and its only appender to A1.

Log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.

Log4j.appender.A1=org.apache.Log4j.ConsoleAppender

# A1 uses PatternLayout.

Log4j.appender.A1.layout=org.apache.Log4j.PatternLayout

Log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

假設我們不在對com.foo包的任何類的輸出感興趣的話,随後的配置檔案向我們展示

了實作這個目的的方法之一。

Log4j.rootLogger=DEBUG, A1

Log4j.appender.A1=org.apache.Log4j.ConsoleAppender

Log4j.appender.A1.layout=org.apache.Log4j.PatternLayout

# Print the date in ISO 8601 format

Log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

# Print only messages of level WARN or above in the package com.foo.

Log4j.logger.com.foo=WARN

以這個配置檔案配置好的MyApp将輸出如下:

2000-09-07 14:07:41,508 [main] INFO MyApp - Entering application.

2000-09-07 14:07:41,529 [main] INFO MyApp - Exiting application.

當logger com.foo.bar沒有被配置設定一個級别,它将從com.foo繼承,在配置檔案中

它被設定了WARN的級别。在Bar.doIt方法中定義的log為DEBUG級别,低于WARN,

是以doIt() 方法的日志請求被禁用。

這裡是另外一個配置檔案,它使用了多個appenders.

Log4j.rootLogger=debug, stdout, R

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

Log4j.appender.R=org.apache.Log4j.RollingFileAppender

Log4j.appender.R.File=example.log

Log4j.appender.R.MaxFileSize=100KB

# Keep one backup file

Log4j.appender.R.MaxBackupIndex=1

Log4j.appender.R.layout=org.apache.Log4j.PatternLayout

Log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

以這個配置檔案調用加強了的MyApp類将輸出如下資訊.

INFO [main] (MyApp2.java:12) - Entering application.

DEBUG [main] (Bar.java:8) - Doing it again!

INFO [main] (MyApp2.java:15) - Exiting application.

另外,因為根logger有被配置設定第二個appender,是以輸出也将被定向到example.log檔案。

這個檔案大小達到100kb時将自動備份。備份時老版本的example.log檔案自動被移到

檔案example.log.1中。

注意我們不需要重新編譯代碼就可以獲得這些不同的日志行為。我們一樣可以容易

的使日志輸出到UNIX Syslog daemon, 重定向所有的com.foo到NT Event logger,

或者轉發日志到一個遠端的Log4j伺服器,它根據本地server的政策來進行日志輸出。例

如轉發日志事件到第二個Log4j伺服器.

5. 預設的初始化過程

Log4j類庫不對它的環境做任何假設。特别是沒有預設的Log4j appender。在一些特别

的有着良好定義的環境下,logger的靜态inializer将嘗試自動的配置Log4j。

java語言的特性保證類的靜态initializer當且僅當裝載類到記憶體之時隻會被調用一次。

要記住的重要一點是,不同的類裝載器可能裝載同一個類的完全不同的拷貝。

這些同樣類的拷貝被虛拟機認為是完全不相幹的。

預設的initialization是非常有用的,特别是在一些應用程式所依靠的運作環境被準确的

定位的情況下。例如,同一樣的應用程式可以被用做一個标準的應用程式,或一個

applet,或一個在web-server控制下的servlet。

準确的預設的initialization原理被定義如下:

1.設定系統屬性Log4j.defaultInitOverride為"false"以外的其它值,那麼Log4j将

跳過預設的initialization過程。

2.設定資源變量字元串給系統屬性Log4j.configuration。定義預設initialization

檔案的最好的方法是通過系統屬性Log4j.configuration。萬一系統屬性

Log4j.configuration沒有被定義,那麼設定字元串變量resource 給它的預設值

Log4j.properties。

3.嘗試轉換resource 變量為一個URL。

4.如果變量resource的值不能被轉換為一個URL,例如由于MalformedURLException違

例,那麼通過調用

org.apache.Log4j.helpers.Loader.getResource(resource, Logger.class) 方法從

classpath中搜尋resource,它将傳回一個URL,并通知"Log4j.properties"的值是一個錯

誤的URL。

看See Loader.getResource(java.lang.String) 檢視搜尋位置的清單。

5.如果沒有URL被發現,那麼放棄預設的initialization。否則用URL配置Log4j。

PropertyConfigurator将用來解析URL,配置Log4j,除非URL以".xml"為結尾。

在這種情況下的話DOMConfigurator将被調用。你可以有機會定義一個自定義的

configurator。

系統屬性Log4j.configuratorClass 的值取自你的自定義的類名的全路徑。

你自定義的configurator必須實作configurator接口。

6. 配置範例

6.1 Tomcat下的初始化

預設的Log4j initialization典型的應用是在web-server 環境下。在tomcat3.x和tomcat4.x

下,你應該将配置檔案Log4j.properties放在你的web應用程式的WEB-INF/classes 目錄

下。

Log4j将發現屬性檔案,并且以此初始化。這是使它工作的最容易的方法。

你也可以選擇在運作tomcat前設定系統屬性Log4j.configuration 。對于tomcat 3.x,

TOMCAT_OPTS 系統變量是用來設定指令行的選項。對于tomcat4.0,用系統環境變

量CATALINA_OPTS 代替了TOMCAT_OPTS。

Example 1

UNIX 指令行

export TOMCAT_OPTS="-DLog4j.configuration=foobar.txt"

告訴Log4j用檔案foobar.txt作為預設的配置檔案。這個檔案應該放在WEB-INF/classes

目錄下。這個檔案将被PropertyConfigurator所讀。每個web-application将用不同的預設

配置檔案,因為每個檔案是和它的web-application 相關的。

Example 2

UNIX 指令行

export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml"

告訴Log4j輸出Log4j-internal的調試資訊,并且用foobar.xml作為預設的配置檔案。

這個檔案應該放在你的web-application的WEB-INF/classes 目錄下。因為有.xml的

擴充名,它将被DOMConfigurator所讀。每個web-application将用不同的預設

配置檔案。因為每個檔案都和它所在的web-application 相關的。

Example 3

UNIX 指令行

set TOMCAT_OPTS=-DLog4j.configuration=foobar.lcf -DLog4j.configuratorClass=com.foo.BarConfigurator

告訴Log4j用檔案foobar.lcf作為預設的配置檔案。這個檔案應該放在你的

web-application的WEB-INF/classes 目錄下。因為定義了Log4j.configuratorClass 系統屬

性,檔案将用自定義的com.foo.barconfigurator類來解析。每個web-application将用不

同的預設配置檔案。因為每個檔案都和它所在的web-application 相關的。

Example 4

UNIX 指令行

set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf

告訴Log4j用檔案foobar.lcf作為預設的配置檔案。這個配置檔案用URL file:/c:/foobar.lcf

定義了全路徑名。這樣同樣的配置檔案将被所有的web-application所用。

不同的web-application将通過它們自己的類裝載器來裝載Log4j。這樣,每個Log4j的環

境将獨立的運作,而沒有任何的互相同步。例如:在多個web-application中定義了

完全相同的輸出源的FileAppenders将嘗試寫同樣的檔案。結果好象是缺乏安全性的。

你必須確定每個不同的web-application的Log4j配置沒有用到同樣的系統資源。

6.2 Servlet 的初始化

用一個特别的servlet來做Log4j的初始化也是可以的。如下是一個例子:

package com.foo;

import org.apache.Log4j.PropertyConfigurator;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.PrintWriter;

import java.io.IOException;

public class Log4jInit extends HttpServlet {

public void init() {

String prefix = getServletContext().getRealPath("/");

String file = getInitParameter("Log4j-init-file");

// if the Log4j-init-file is not set, then no point in trying

if(file != null) {

PropertyConfigurator.configure(prefix+file);

}

}

public void doGet(HttpServletRequest req, HttpServletResponse res) {

}

}

在web.xml中定義随後的servlet為你的web-application。

Log4j-init

com.foo.Log4jInit

Log4j-init-file

WEB-INF/classes/Log4j.lcf

1

寫一個初始化的servlet是最有彈性的初始化Log4j的方法。代碼中沒有任何限制,你可

以在servlet的init方法中定義它。