說(shuō)實(shí)話(huà),除了log4j的功能外,我更喜歡它的logo.
下面的這篇筆記,主要是"borrow from"Log4J的隨機文檔"Short introduction to log4j",由Ceki Gülcü 寫(xiě)于March 2002,其它參考文檔見(jiàn)文后。1、log4j已經(jīng)被移植到C, C++, C#, Perl, Python, Ruby, Eiffel 幾種語(yǔ)言。
2、log4j有三種主要的組件:記錄器,存放器,布局
3、記錄器(記錄器可不關(guān)心log數據存放的事喲)
log4j允許程序員定義多個(gè)記錄器,每個(gè)記錄器有自己的名字,記錄器之間通過(guò)名字來(lái)表明隸屬關(guān)系(或家族關(guān)系)。列如,記錄器a.b,與記錄器a.b.c之間是父子關(guān)系,而記錄器a與a.b.c之間是祖先與后代的關(guān)系,父子關(guān)系是祖先與后代關(guān)系的特例。通過(guò)這種關(guān)系,可以描述不同記錄器之間的邏輯關(guān)系。
有一個(gè)記錄器叫根記錄器,它永遠存在,且不能通過(guò)名字檢索或引用,可以通過(guò)Logger.getRootLogger()方法取得它,而一般記錄器通過(guò)Logger.getLogger(String name)方法。下面是Logger類(lèi)的基本方法。package org.apache.log4j;public class Logger {
// Creation & retrieval methods:
public static Logger getRootLogger();
public static Logger getLogger(String name);// printing methods:
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);// generic printing method:
public void log(Level l, Object message);
}
記錄器還有一個(gè)重要的屬性,就是級別。(這好理解,就象一個(gè)家庭中,成員間存在輩份關(guān)系,但不同的成員的身高可能不一樣,且身高與輩份無(wú)關(guān))程序員可以給不同的記錄器賦以不同的級別,如果某個(gè)成員沒(méi)有被明確值,就自動(dòng)繼承最近的一個(gè)有級別長(cháng)輩的級別值。根記錄器總有級別值。例如:
記錄器名 賦予的級別值 繼承的級別值 root Proot Proot X Px Px X.Y none Px X.Y.Z none Px
程序員可以自由定義級別。級別值之間存在偏序關(guān)系,如上面幾種級別就有關(guān)系DEBUG<><><><>
每一條要輸出的log信息,也有一個(gè)級別值。
前面的Logger類(lèi)中,就預定義了 DEBUG, INFO, WARN, ERROR ,FATAL幾種級別,由于與方法綁定,讓人易產(chǎn)生誤解,其實(shí)這幾個(gè)方法只不過(guò)表明了要記錄的log信息的級別。當調用log()方法時(shí),log信息的級別就需要在通過(guò)參數明確指定。
如果一條log信息的級別,大于等于記錄器的級別值,那么記錄器就會(huì )記錄它。如果你覺(jué)得難以理解,可參考下例。// get a logger instance named "com.foo"
Logger logger = Logger.getLogger("com.foo");// Now set its level. Normally you do not need to set the
// level of a logger programmatically. This is usually done
// in configuration files.
logger.setLevel(Level.INFO);Logger barlogger = Logger.getLogger("com.foo.Bar");
// This request is enabled, because WARN >= INFO.
logger.warn("Low fuel level.");// This request is disabled, because DEBUG < INFO.
logger.debug("Starting search for nearest gas station.");// The logger instance barlogger, named "com.foo.Bar",
// will inherit its level from the logger named
// "com.foo" Thus, the following request is enabled
// because INFO >= INFO.
barlogger.info("Located nearest gas station.");// This request is disabled, because DEBUG < INFO.
barlogger.debug("Exiting gas station search");
有幾個(gè)有趣的情況,一是當一個(gè)記錄器實(shí)例化后,再一次用相同的名字調用getLogger()會(huì )返回對它的引用,這非常有利于用同一個(gè)記錄器在不同代碼或類(lèi)中記錄log信息,另一個(gè)是與自然界中祖先先于后代出現不同,一個(gè)記錄器的祖先可以比后代記錄出現的晚,但會(huì )自動(dòng)根據名字之間的關(guān)系建立這種家族關(guān)系。4、存放器
在log4j中,log信息通過(guò)存放器輸出到目的地。支持的存放器有console, files, GUI components, remote socket servers, JMS, NT Event Loggers, remote UNIX Syslog daemons。通過(guò)file存放器,log信息可以被輸出到不同的文件中(即不同的目的地)。log信息可被異步存放。
一個(gè)記錄器可以有多個(gè)存放器,可以通過(guò)方法addAppender來(lái)增加存放器。一條blog信息如果可被這個(gè)記錄器處理,則記錄器會(huì )把這條信息送往每個(gè)它所擁有的存放器。
每個(gè)記錄器有一個(gè)繼承開(kāi)關(guān),其開(kāi)關(guān)決定記錄器是/否繼承其父記錄器的存放器,注意,如果繼承則只繼承其父記錄器,而不考慮更遠的祖先的情況。參考下表:
記錄器 增加的存放器 繼承的存放器 輸出的目的地 備注 root A1 not applicable A1 The root logger is anonymous but can be accessed with the Logger.getRootLogger() method. There is no default appender attached to root. x A-x1, A-x2 TRUE A1, A-x1, A-x2 Appenders of "x" and root. x.y none TRUE A1, A-x1, A-x2 Appenders of "x" and root. x.y.z A-xyz1 TRUE A1, A-x1, A-x2, A-xyz1 Appenders in "x.y.z", "x" and root. security A-sec FALSE A-sec No appender accumulation since the additivity flag is set to false. security.access none TRUE A-sec Only appenders of "security" because the additivity flag in "security" is set to false.
5、布局
布局負責格式化輸出的log信息。log4j的PatternLayout可以讓程序以類(lèi)似C語(yǔ)言printf的格式化模板來(lái)定義格式。6、log4j可據程序員制定的標準自動(dòng)提供一些log信息,這對那類(lèi)需要頻繁log的對象的情況很幫助。對象的自動(dòng)log,具有繼承性。
參考文獻:
1、log4j--新的日志操作方法,scriptskychen ,http://www.cn-java.com/target/news.php?news_id=2590
前面主要記了一些原理,這次是實(shí)務(wù)。
1、研究發(fā)現,一個(gè)系統中4%的代碼是用來(lái)作logging的。
2、Log4J的配置文件(Configuration File)就是用來(lái)設置記錄器的級別、存放器和布局的,它可接key=value格式的設置或xml格式的設置信息。通過(guò)配置,可以創(chuàng )建出Log4J的運行環(huán)境。
Log4J運行時(shí),不對環(huán)境做任何假定,尤其是沒(méi)有默認的存放器。
3、有幾種方式可以配置Log4J
1)在程序中調用BasicConfigurator.configure()方法;
2)配置放在文件里,通過(guò)命令行參數傳遞文件名字,通過(guò)PropertyConfigurator.configure(args[x])解析并配置;
3)配置放在文件里,通過(guò)環(huán)境變量傳遞文件名等信息,利用log4j默認的初始化過(guò)程解析并配置;
4)配置放在文件里,通過(guò)應用服務(wù)器配置傳遞文件名等信息,利用一個(gè)特殊的servlet來(lái)完成配置。
看下面的例子: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.");
}
}
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給根記錄器增加一個(gè)ConsoleAppender,輸出格式通過(guò)PatternLayout設為"%-4r [%t] %-5p %c %x - %m%n",還有根記錄器的默認級別是Level.DEBUG.
記錄器之間的關(guān)系如下圖:
輸出結果如下:0 [main] INFO MyApp - Entering application.
36 [main] DEBUG com.foo.Bar - Did it again!
51 [main] INFO MyApp - Exiting application.
下面的代碼結合配置信息,會(huì )得到與上述程序一樣的結果。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.");
}
}配置文件的內容如下:
# 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利用配置文件,可以很方便地修改配置。如下例
log4j.rootLogger=debug, stdout, Rlog4j.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
# Print the date in ISO 8601 format
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%nlog4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.loglog4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n# Print only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN
對于tomcat4,利用環(huán)境變量傳遞參數的,可參見(jiàn)以下幾個(gè)例子
unix設置
export CATALINA_OPTS ="-Dlog4j.configuration=foobar.txt"<===用PropertyConfigurator解析
export CATALINA_OPTS ="-Dlog4j.debug -Dlog4j.configuration=foobar.xml"<===用DOMConfigurator解析
以下是windows設置
set CATALINA_OPTS =-Dlog4j.configuration=foobar.lcf -Dlog4j.configuratorClass=com.foo.BarConfigurator<===用com.foo.BarConfigurator解析
set CATALINA_OPTS =-Dlog4j.configuration=file:/c:/foobar.lcf配置文件位置如果沒(méi)有明確指明,則要放在WEB-INF/classes目錄下。
4、用servlet配置log4j
以下都是參考冰之火的文章,抄來(lái)放在這兒,并做了一些必要的修改。需要說(shuō)明的是,下面的代碼需要自己寫(xiě)并發(fā)布,下的jar中沒(méi)有這個(gè)類(lèi)。待我以后寫(xiě)一個(gè),也放上來(lái)。我也寫(xiě)了兩個(gè),在筆記(三)中。
在A(yíng)pplication目錄下的web.xml文件加入以后代碼<servlet>
<servlet-name>log4jlog4j-init</servlet-name>
<servlet-class>com.apache.jakarta.log4j.Log4jInit</servlet-class>
<init-param>
<param-name>log4j</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
這段代碼的意思是說(shuō),在Tomcat啟動(dòng)時(shí)加載com.apache.jakarta.log4j.Log4jInit這個(gè)名叫Log4jInit.class這個(gè)類(lèi)文件。
其中Log4jInit.class的源代碼如下
package com.apache.jakarta.log4j;
import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Log4jInit extends HttpServlet {public void init() {
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j");
// if the log4j-init-file is not set, then no point in trying
System.out.println("................log4j start");
if(file != null) {
PropertyConfigurator.configure(prefix+file);
}
}
public void doGet(HttpServletRequest req, HttpServletResponse res) {
}
}
在加載的過(guò)程中,程序會(huì )讀取/WEB-INF/log4j.properties這個(gè)文件。
配置文件講解如下:# Set root logger level to DEBUG and its only appender to A1
#log4j中有五級logger
#FATAL 0
#ERROR 3
#WARN 4
#INFO 6
#DEBUG 7
#配置根Logger,其語(yǔ)法為:
#log4j.rootLogger = [ level ] , appenderName, appenderName, …
log4j.rootLogger=INFO, A1 ,R
#這一句設置以為著(zhù)所有的log都輸出
#如果為log4j.rootLogger=WARN, 則意味著(zhù)只有WARN,ERROR,FATAL
#被輸出,DEBUG,INFO將被屏蔽掉.
# A1 is set to be a ConsoleAppender.
#log4j中Appender有幾層如控制臺、文件、GUI組件、甚至是套接口服務(wù)器、NT的事件記錄器、UNIX Syslog守護進(jìn)程等
#ConsoleAppender輸出到控制臺
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 使用的輸出布局,其中log4j提供4種布局. org.apache.log4j.HTMLLayout(以HTML表格形式布局)
#org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
#org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
#org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線(xiàn)程、類(lèi)別等等信息)log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#靈活定義輸出格式 具體查看log4j javadoc org.apache.log4j.PatternLayout
#d 時(shí)間 ....
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
#R 輸出到文件 RollingFileAppender的擴展,可以提供一種日志的備份功能。
log4j.appender.R=org.apache.log4j.RollingFileAppender
#日志文件的名稱(chēng)
log4j.appender.R.File=log4j.log
#日志文件的大小
log4j.appender.R.MaxFileSize=100KB
# 保存一個(gè)備份文件
log4j.appender.R.MaxBackupIndex=1log4j.appender.R.layout=org.apache.log4j.TTCCLayout
#log4j.appender.R.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
配置根Logger,其語(yǔ)法為:log4j.rootLogger = [ level ] , appenderName, appenderName, ...
level 是日志記錄的優(yōu)先級
appenderName就是指定日志信息輸出到哪個(gè)地方。您可以同時(shí)指定多個(gè)輸出目的地。配置日志信息輸出目的地Appender,其語(yǔ)法為
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
...
log4j.appender.appenderName.option = valueN
Log4j提供的appender有以下幾種:
org.apache.log4j.ConsoleAppender(控制臺),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件),
org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時(shí)候產(chǎn)生一個(gè)新的文件),
org.apache.log4j.WriterAppender(將日志信息以流格式發(fā)送到任意指定的地方)配置日志信息的格式(布局),其語(yǔ)法為:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
....
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(包含日志產(chǎn)生的時(shí)間、線(xiàn)程、類(lèi)別等等信息)
我這兒有兩個(gè)程序,一個(gè)是普通的java程序,實(shí)現了一個(gè)“九九表”;另一個(gè)是servlet。我這兒用的tomcat是4.1.12,J2SE是1.3.1,log4j的版本是1.2.8.
一、九九表。
環(huán)境設置:需要將log4j-1.2.8.jar放入CLASSPATH變量中。
Hello.java文件的內容如下:import org.apache.log4j.*;
public class Hello{
static Logger logger = Logger.getLogger(Hello.class);
public static void main(String[] args) {
int i,j;
// BasicConfigurator.configure();
PropertyConfigurator.configure(args[0]);
logger.info("Entering application.");
for(i=1;i<10;i++){
logger.debug(""+i);
for (j=1;j<=i;j++){
logger.warn(""+j);
System.out.print(i*j);
System.out.print("\t");
}
System.out.println("");
}
logger.info("Exiting application.");
}
log4j的配置文件log4j.inf的內容如下:log4j.rootLogger=WARN, 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
# Print the date in ISO 8601 format
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %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
# Print only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN
運行:javac Hello.java
java Hello log4j.inf
結果會(huì )在屏幕上顯示,并在example.log文件中記錄。二、servlet
環(huán)境設置:將log4j-1.2.8.jar及servlet.jar放入環(huán)境變量CLASSPATH中,并且要將log4j-1.2.8復制到$TOMCAT_HOME/common/lib目錄下。
假定,有一個(gè)布署到tomcat的應用叫myweb。
servlet程序Log4jInit.java的位置在$TOMCAT_HOME/webapps/myweb/WEB-INF/classes/com/hedong/learning/log4j/目錄下,內容如下:package com.hedong.learning.log4j;
import org.apache.log4j.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Log4jInit extends HttpServlet {
public void init() {
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j");
// if the log4j-init-file is not set, then no point in trying
System.out.println("................log4j start");
if(file != null) {
PropertyConfigurator.configure(prefix+file);
}
}
public void doGet(HttpServletRequest req, HttpServletResponse res) {
}
}
在Log4jInit.java所在目錄下編譯它:javac Log4jInit.java
myweb的設置文件web.xml在$TOMCAT_HOME/webapps/myweb/WEB-INF/目錄下,增加如下紅色部分。</web-app>
...........
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>com.hedong.learning.log4j.Log4jInit</servlet-class>
<init-param>
<param-name>log4j</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
同時(shí),在這個(gè)目錄下建一個(gè)文件名叫log4j.properties,內容如下:log4j.rootLogger=INFO, A1 , R
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=$TOMCAT_HOME/webapps/dbweb/logs/log4j.log<----將$TOMCAT_HOME換成tomcat的安裝目錄
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
記住,別忘了創(chuàng )建目錄$TOMCAT_HOME/webapps/dbweb/logs/,如果它不存在的話(huà)。
創(chuàng )建目錄$TOMCAT_HOME/webapps/dbweb/test/,然后在這個(gè)目錄下新建一個(gè)文件test.jsp,內容如下:<%@ page contentType="text/html; charset=GB2312" %>
<%@ page import="org.apache.log4j.*" %>
<%
Logger logger = Logger.getLogger("test.jsp");
logger.info("befor say hi");
%>
<h1> Hi</h1>
<%
logger.info("after say hi");
%>
然后,重新啟動(dòng)tomcat,通過(guò)瀏覽器訪(fǎng)問(wèn)這個(gè)jsp頁(yè)面,如http://yourdomain.com:8080/myweb/test/test.jsp,如果一切正常,會(huì )看到一個(gè)大大的HI。然后,在服務(wù)器上的$TOMCAT_HOME/webapps/dbweb/logs/log4j.log文件中看到如下的信息:INFO HttpProcessor[8080][4] test.jsp - befor say hi
INFO HttpProcessor[8080][4] test.jsp - after say hi。在默認的情況下,tomcat的屏幕輸出被重定向到$TOMCAT_HOME/logs/catalina.out文件中,在文件的最后也應看到上述的輸出。
聯(lián)系客服