Log4j簡(jiǎn)明手冊(cè)
1. 概述
本文主要描述Log4j的API的唯一特性和它的設(shè)計(jì)原理。Log4j是一個(gè)基于許多作者的開(kāi)放源碼的項(xiàng)目。它允許開(kāi)發(fā)員以任意的間隔來(lái)控制日志的輸出。它通過(guò)設(shè)在外部的配置文件而達(dá)到運(yùn)行時(shí)靈活的設(shè)置。最重要的是,Log4j有一個(gè)平穩(wěn)的學(xué)習(xí)曲線。注意:根據(jù)來(lái)自用戶的反饋判斷,它很容易使人上癮。
2. 導(dǎo)言
幾乎所有的大型應(yīng)用程序都包括它的自己的日志和跟蹤API。順應(yīng)這個(gè)規(guī)則,E.U. SEMPER 項(xiàng)目決定寫(xiě)它自己的跟蹤PAI。這是1996年初。在無(wú)數(shù)次加強(qiáng),幾次變形和許多工作后,那個(gè)API變成了如今的Log4j,一個(gè)流行的java日志包。這個(gè)包以Apache Software License協(xié)議發(fā)布,一個(gè)成熟的開(kāi)放源嗎協(xié)議。最新的Log4j版本,包括全部的源碼,class文件和文檔,你可以在http://jakarta.apache.org/Log4j/上找到。順便,Log4j已經(jīng)給C, C++, C#, Python, Ruby, and Eiffel 語(yǔ)言都提供了接口。
為了調(diào)試而插入日志輸出到代碼里是一個(gè)低技術(shù)成分的方法,但它可能也是唯一的方法,因?yàn)檎{(diào)試器并不是一直可用或者可以適應(yīng)的,尤其對(duì)于多線程的分布使式的大型程序而言。
經(jīng)驗(yàn)指出調(diào)試是軟件開(kāi)發(fā)周期中一個(gè)重要的組成部分。
Log4j擁有幾個(gè)優(yōu)點(diǎn):
首先,它提供關(guān)于運(yùn)行程序的準(zhǔn)確的環(huán)境。一旦代碼被插入,不需要人工干預(yù)就可以產(chǎn)生調(diào)試信息。
其次,日志輸出可以被有計(jì)劃的保存在永久媒體中以便日后研究。
另外,除了在開(kāi)發(fā)周期中,一個(gè)充分詳盡的日志包可以被用來(lái)作為以后的統(tǒng)計(jì)工具。
Log4j當(dāng)然還有它的缺點(diǎn),它可能減慢程序。如果太詳細(xì),它可能導(dǎo)致屏幕盲目滾動(dòng)。排除這些情況,Log4j是可靠的,快速的,可以擴(kuò)展的。因?yàn)槿罩竞苌偈且粋€(gè)應(yīng)用程序的主要目的, 設(shè)計(jì)者們正努力使得Log4j API學(xué)習(xí)和使用簡(jiǎn)單化。
3. 日志類別、輸出源和布局
Log4j有三個(gè)主要的組件:日志類別(Loggers)、輸出源( Appenders)和布局(Layouts)。這三種類型的組件一起工作使得開(kāi)發(fā)員可以根據(jù)信息的類型和級(jí)別記錄它們,并且在運(yùn)行時(shí)控制這些信息的輸出格式和位置。
3.1 日志類別的層次結(jié)構(gòu)(Loggers)
Log4j首要的相對(duì)于簡(jiǎn)單的使用System.out.println()方法的優(yōu)點(diǎn)是基于它的在禁止一些特定的信息輸出的同時(shí)不妨礙其它信息的輸出的能力。這個(gè)能力源自于日志命名空間,也就是說(shuō),所有日志聲明的空間,它根據(jù)一些開(kāi)發(fā)員選擇的公式而分類。以前的觀察引導(dǎo)我們選擇類別作為包的中心概念。然而,自從Log4j的1.2版本,Logger類被Catalog類所取代,對(duì)于那些熟悉Log4j以前版本的人來(lái)說(shuō),Logger類可以被想象成僅僅是Category 類的別名。
Loggers 被指定為實(shí)體,Logger的名字是大小寫(xiě)敏感的,它們遵循以下的命名
規(guī)則:
2 命名繼承
如果類別的名稱(后面加一個(gè)點(diǎn))是其子類別名稱的前綴,則它就是另一個(gè)類別的祖輩。
如果一個(gè)類別(Logger)和它的子類別之間沒(méi)有其它的繼承關(guān)系,我們就稱之為parent與child的關(guān)系。
例如,類別"com.foo"是類別"com.foo.Bar"的parent。相似的,"java"是"java.util"的parent,是"java.util.Vector"的父輩。.這個(gè)命名規(guī)則應(yīng)該被大多數(shù)的開(kāi)發(fā)員所熟悉。
根(root) 類別位于logger繼承結(jié)構(gòu)的最上層。它有兩種例外:
1.它一直存在
2.它不能根據(jù)名稱而獲得。
調(diào)用類的靜態(tài)方法Logger.getRootLogger可以得到它。其它所有的Logger可以通過(guò)靜態(tài)方法Logger.getLogger而得到它們自己的實(shí)例。這個(gè)方法取希望的Logger名作為參數(shù)。Logger的一些基本的方法示例如下:
package org.apache.Log4j;
public Logger class {
// 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);
// generic printing method:
public void log(Level l, Object message);
}
Loggers可以被分配的級(jí)別。所有級(jí)別的集合包括:
DEBUG
INFO
WARN
ERROR
FATAL
它們被定義于org.apache.Log4j.Level 類。雖然我們不鼓勵(lì),但是你們可以通過(guò)繼承Level類來(lái)定義你們自己的級(jí)別。我們隨后將介紹一個(gè)比較好的方法。
如果一個(gè)Logger沒(méi)有被分配一個(gè)級(jí)別,那么它將從一個(gè)被分配了級(jí)別的最接近它的ancestor哪里繼承。
正規(guī)的說(shuō):
2 級(jí)別繼承
對(duì)于一個(gè)給定的Logger C,它的繼承的級(jí)別等于從C開(kāi)始上溯到的第一個(gè)擁有非空級(jí)別的Logger的級(jí)別。
為了保證所有的Logger最終能夠繼承到一個(gè)級(jí)別,根Logger通常有一個(gè)已經(jīng)定義了的級(jí)別。
以下四個(gè)表中的數(shù)據(jù)演示了根據(jù)以上規(guī)則得到的結(jié)果。
類別名
分配的級(jí)別
繼承的級(jí)別
root
Proot
Proot
X
none
Proot
X.Y
none
Proot
X.Y.Z
none
Proot
Example 1
在例子1中,只有根Logger定義了一個(gè)級(jí)別,它的級(jí)別的值--"Proot"被所有其它的Loggers X, X.Y, 和X.Y.Z所繼承。
類別名
分配的級(jí)別
繼承的級(jí)別
root
Proot
Proot
X
Px
Px
X.Y
Pxy
Pxy
X.Y.Z
Pxyz
Pxyz
Example 2
在例子2中,所有的Logger都有一個(gè)被分配的級(jí)別值,所以它們不需要級(jí)別繼承。
類別名
分配的級(jí)別
繼承的級(jí)別
root
Proot
Proot
X
Px
Px
X.Y
none
Px
X.Y.Z
Pxyz
Pxyz
Example 3
在例子3中,根Logger,以及X和X.Y.Z被分別分配了級(jí)別Proot,Px和Pxyz。Logger X.Y從它的parent X繼承了級(jí)別值Px。
類別名
分配的級(jí)別
繼承的級(jí)別
root
Proot
Proot
X
Px
Px
X.Y
none
Px
X.Y.Z
none
Px
Example 4
在例子4中,根Logger和X被分別分配了級(jí)別"Proot"和"Px",Logger X.Y 和 X.Y.Z從被分配了級(jí)別的最接近它們的ancestor X那里得到繼承。
我們需要通過(guò)調(diào)用Logger的輸出的實(shí)例方法之一來(lái)實(shí)現(xiàn)日志請(qǐng)求。這些輸出的方法是debug, info, warn, error, fatal 和 log.
通過(guò)定義輸出方法來(lái)區(qū)分日志的請(qǐng)求的級(jí)別。例如,如果c是一個(gè)Logger的實(shí)例,那么聲明 c.info 就是一個(gè)INFO級(jí)別的日志請(qǐng)求。
如果一個(gè)日志的請(qǐng)求的級(jí)別高于或等于日志的級(jí)別那么它就能被啟用。反之,將被禁用。一個(gè)沒(méi)有被安排級(jí)別的Logger將從它的父輩中得到繼承。這個(gè)規(guī)則總結(jié)如下。
2 基本的選擇規(guī)則
假如在一個(gè)級(jí)別為q的Logger中發(fā)生一個(gè)級(jí)別為p的日志請(qǐng)求,如果p>=q,那么請(qǐng)求將被啟用。
這是Log4j的核心原則。它假設(shè)級(jí)別是有序的。對(duì)于標(biāo)準(zhǔn)級(jí)別,我們定義DEBUG < INFO < WARN < ERROR < FATAL.
以下是關(guān)于這條規(guī)則的一個(gè)例子。
// 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 progamitcally. This is usually done
// in configuration files.
cat.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方法將返回一個(gè)同名的Logger對(duì)象的實(shí)例。
例如,
Categoty x = Logger.getLogger("wombat");
Categoty y = Logger.getLogger("wombat");
x和y參照的是同一個(gè)Logger對(duì)象。
這樣我們就可以先定義一個(gè)Logger,然后在代碼的其它地方不需傳參就可以重新得到我們已經(jīng)定義了的Logger的實(shí)例.
同基本的生物學(xué)理論--父先于子相反,Log4j 的loggers可以以任何順序創(chuàng)造和配置。特別是,一個(gè)后實(shí)例化的"parent"logger能夠找到并且連接它的子logger。
配置Log4j的環(huán)境通常在一個(gè)應(yīng)用程序被初始化的時(shí)候進(jìn)行,最好的方法是通過(guò)讀一個(gè)配置文件。這個(gè)方法我們將簡(jiǎn)短介紹。
Log4j使得通過(guò)軟件組件命名logger很容易。我們可以通過(guò)Logger的靜態(tài)的初始化方法在每一個(gè)類里定義一個(gè)logger,令logger的名字等于類名的全局名,而實(shí)現(xiàn)logger的命名。這是一個(gè)實(shí)效的簡(jiǎn)單的定義一個(gè)logger的方法。因?yàn)槿罩据敵鰩в挟a(chǎn)生日志的類的名字,這個(gè)命名策略使得我們更容易定位到一個(gè)日志信息的來(lái)源。雖然普通,但卻是命名logger的常用策略之一。Log4j沒(méi)有限制定義logger的可能。開(kāi)發(fā)員可以自由的按照它們的意愿定義logger的名稱。
然而,以類的所在位置來(lái)命名Logger好象是目前已知的最好方法。
3.2 輸出源(Appenders)和布局(Layouts)
有選擇的能用或者禁用日志請(qǐng)求僅僅是Log4j的一部分功能。Log4j允許日志請(qǐng)求被輸出到多個(gè)輸出源。用Log4j的話說(shuō),一個(gè)輸出源被稱做一個(gè)Appender. 。Appender包括console(控制臺(tái)), files(文件), GUI components(圖形的組件), remote socket servers(socket 服務(wù)), JMS(java信息服務(wù)), NT Event Loggers(NT的事件日志), and remote UNIX Syslog daemons(遠(yuǎn)程UNIX的后臺(tái)日志服務(wù))。它也可以做到異步記錄。
一個(gè)logger可以設(shè)置超過(guò)一個(gè)的appender。
用addAppender 方法添加一個(gè)appender到一個(gè)給定的logger。對(duì)于一個(gè)給定的logger它每個(gè)生效的日志請(qǐng)求都被轉(zhuǎn)發(fā)到該logger所有的appender上和該logger的父輩logger的appender上。換句話說(shuō),appender自動(dòng)從它的父輩獲得繼承。舉例來(lái)說(shuō),如果一個(gè)根logger擁有一個(gè)console appender,那么所有生效的日志請(qǐng)求至少會(huì)被輸出到console上。如果一個(gè)名為C的logger有一個(gè)file類型的appender,那么它就會(huì)對(duì)它自己以及所有它的子logger生效。我們也可以通過(guò)設(shè)置appender的additivity flag 為false,來(lái)重載appender的默認(rèn)行為,以便繼承的屬性不在生效。
調(diào)節(jié)輸出源(appender)添加性的規(guī)則如下。
輸出源的可添加性(Appender Additivity )
一個(gè)名為C的logger的日志定義的輸出將延續(xù)到它自身以及它的ancestor logger的appenders。這就是術(shù)語(yǔ)"appender additivity"的含義。
然而,logger C的一個(gè)ancestor logger P,它的附加標(biāo)志被設(shè)為false,那么C的輸出將被定位到所有C的appender,以及從它開(kāi)始上溯到P的所有ancestor logger的appender。
Loggers的附加標(biāo)記(additivity flag)默認(rèn)為true。
下表是一個(gè)例子。
Logger
Name
Added
Appenders
Additivity
Flag
Output Targets
Comment
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.
經(jīng)常,用戶希望自定義不但輸出源,而且定義輸出格式。這個(gè)是通過(guò)在一個(gè)appender上附加一個(gè)layout來(lái)完成的。layout是負(fù)責(zé)根據(jù)用戶的希望來(lái)格式化日志請(qǐng)求。而appender是負(fù)責(zé)發(fā)送格式化的輸出到它的目的地。PatternLayout,作為L(zhǎng)og4j標(biāo)準(zhǔn)版中的一部分,讓用戶指以類似C語(yǔ)言的printf方法的格式來(lái)指定日志的輸出格式。
例如,轉(zhuǎn)化模式為"%r [%t] %-5p %c - %m%n" 的PatternLayout 將輸出類似如下的信息:
176 [main] INFO org.foo.Bar - Located nearest gas station.
第一個(gè)欄位是自從程序開(kāi)始后消逝的毫秒數(shù)。
第二個(gè)欄位是做出日志的線程。
第三個(gè)欄位是log的級(jí)別。
第四個(gè)欄位是日志請(qǐng)求相關(guān)的logger的名字。而"-"后的文字是信息的表述。
Log4j將根據(jù)用戶定義的公式來(lái)修飾日志信息的內(nèi)容。例如,如果你經(jīng)常需要記錄Oranges,一個(gè)在你當(dāng)前的項(xiàng)目被用到的對(duì)象類型,那么你可以注冊(cè)一個(gè)OrangeRenderer ,它將在一個(gè)orange需要被記錄時(shí)被調(diào)用。
對(duì)象渲染類似的類的結(jié)構(gòu)繼承。例如,假設(shè)oranges是fruits,如果你注冊(cè)了一個(gè)FruitRenderer,所有的水果包括oranges將被FruitRenderer所渲染。除非你注冊(cè)了一個(gè)orange。
對(duì)象渲染必須實(shí)現(xiàn)ObjectRenderer接口。
posted on 2007-01-03 17:00
???MengChuChen 閱讀(275)
評(píng)論(0) 編輯 收藏 所屬分類:
Log4j