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方法中定義它。
posted on 2007-01-03 17:03
???MengChuChen 閱讀(340)
評論(0) 編輯 收藏 所屬分類:
Log4j