原文地址:http://www.infomall.cn/cgi-bin/mallgate/20031008/http://hedong.3322.org/archives/000193.html
說實話,除了log4j的功能外,我更喜歡它的logo.
下面的這篇筆記,主要是"borrow from"Log4J的隨機文檔"Short introduction to log4j",由Ceki Gülcü 寫于March 2002,其它參考文檔見文后。
1、log4j已經(jīng)被移植到C, C++, C#, Perl, Python, Ruby, Eiffel 幾種語言。
2、log4j有三種主要的組件:記錄器,存放器,布局
3、記錄器(記錄器可不關(guān)心log數(shù)據(jù)存放的事喲)
log4j允許程序員定義多個記錄器,每個記錄器有自己的名字,記錄器之間通過名字來表明隸屬關(guān)系(或家族關(guān)系)。列如,記錄器a.b,與記錄器a.b.c之間是父子關(guān)系,而記錄器a與a.b.c之間是祖先與后代的關(guān)系,父子關(guān)系是祖先與后代關(guān)系的特例。通過這種關(guān)系,可以描述不同記錄器之間的邏輯關(guān)系。
有一個記錄器叫根記錄器,它永遠存在,且不能通過名字檢索或引用,可以通過Logger.getRootLogger()方法取得它,而一般記錄器通過Logger.getLogger(String name)方法。下面是Logger類的基本方法。
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);
}
記錄器還有一個重要的屬性,就是級別。(這好理解,就象一個家庭中,成員間存在輩份關(guān)系,但不同的成員的身高可能不一樣,且身高與輩份無關(guān))程序員可以給不同的記錄器賦以不同的級別,如果某個成員沒有被明確值,就自動繼承最近的一個有級別長輩的級別值。根記錄器總有級別值。例如:
記錄器名 |
賦予的級別值 |
繼承的級別值 |
root |
Proot |
Proot |
X |
Px |
Px |
X.Y |
none |
Px |
X.Y.Z |
none |
Px |
程序員可以自由定義級別。級別值之間存在偏序關(guān)系,如上面幾種級別就有關(guān)系DEBUG
每一條要輸出的log信息,也有一個級別值。
前面的Logger類中,就預定義了 DEBUG, INFO, WARN, ERROR ,F(xiàn)ATAL幾種級別,由于與方法綁定,讓人易產(chǎn)生誤解,其實這幾個方法只不過表明了要記錄的log信息的級別。當調(diào)用log()方法時,log信息的級別就需要在通過參數(shù)明確指定。
如果一條log信息的級別,大于等于記錄器的級別值,那么記錄器就會記錄它。如果你覺得難以理解,可參考下例。
// 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");
有幾個有趣的情況,一是當一個記錄器實例化后,再一次用相同的名字調(diào)用getLogger()會返回對它的引用,這非常有利于用同一個記錄器在不同代碼或類中記錄log信息,另一個是與自然界中祖先先于后代出現(xiàn)不同,一個記錄器的祖先可以比后代記錄出現(xiàn)的晚,但會自動根據(jù)名字之間的關(guān)系建立這種家族關(guān)系。
4、存放器
在log4j中,log信息通過存放器輸出到目的地。支持的存放器有console, files, GUI components, remote socket servers, JMS, NT Event Loggers, remote UNIX Syslog daemons。通過file存放器,log信息可以被輸出到不同的文件中(即不同的目的地)。log信息可被異步存放。
一個記錄器可以有多個存放器,可以通過方法addAppender來增加存放器。一條blog信息如果可被這個記錄器處理,則記錄器會把這條信息送往每個它所擁有的存放器。
每個記錄器有一個繼承開關(guān),其開關(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可以讓程序以類似C語言printf的格式化模板來定義格式。
6、log4j可據(jù)程序員制定的標準自動提供一些log信息,這對那類需要頻繁log的對象的情況很幫助。對象的自動log,具有繼承性.
參考文獻:
1、log4j--新的日志操作方法,scriptskychen ,http://www.cn-java.com/target/news.php?news_id=2590