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