由于自己工作性質發生了些變化,人隨境遷,回首時,發現真的是歲月如梭,時光如水。彈指間,從研發到維護,從總部到出差已經是四月有余了。
在維護系統時,難免會時不時地跟代碼再次打些交道。今天想再操刀做個小工具時,居然不太記得了log4j的配置,不得不從apache再重新down了相關的jar與DOC,匆匆看看了一下,快點寫下來,日后肯定還用得著,同時也希望對網友們有用。
Log4j基本上已經是java里的首選日志工具了,它主要由三部分組成:Loggers, Appenders和Layouts (注意后面都加了s啦,顧名思義一個配置中可以分別允許有多個此類對象存在,后面將詳細介紹)。
Loggers-用來定義日志消息的類型及級別;
Appenders-用來定義日志消息的輸出終端;
Layouts-用來定義日志消息的輸出格式。
Logger
Loggers層次:
對logger的名字是大小寫敏感。
規則-如果類P的名字是另一個類C的名字的前綴,且P與C之間以“.”號連接起來,那么稱P為祖先層次;如果層次A與其子層次之間沒有任何父層次,則認為層次A為父層次。
|
例如,org.apache.log4j是org.apache.log4j.Logger的父層次;而org.apache是org.apache.log4j與org.apache.log4j.Logger的祖先層次。
另外,注意log4j中有個默認的root級別的logger,在所有logger中,它是最高級別,其它所有logger均繼承于root,root有以下二個特性:
1. 它總是存在的。
2. 它不能通過名字直接獲取其實例(root實例可以通過類Logger的靜態方法Logger.getRootLogger獲得,而其它logger則可以直接通過名字來獲取Logger.getLogger)。
關于Loggers中的級別:
對每個logger,可以指定其級別,在系統org.apache.log4j.Level中,已經定義了五個級別,分別為debug, info, warn, error, fatal。
規則-設當前logger為X,從X開始往X的父類方向開始算(包括X本身),直到名為root的logger,第一個不為null的級別值就是X的級別值。
|
日志顯示:
級別的定義是為了過濾性地選擇日志。
規則-若當前請方式級別為P,而當前的logger的級別為Q,當且僅當在P>=Q的情況下,日志信息才能顯示。
|
關于日志中級別的關系為:DEBUG < INFO < WARN < ERROR < FATAL
。
關于此規則的說明,有以下代碼為實例:
// 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");
|
Appenders與Layouts
Appender正如前面所述,是用來定義日志信息的輸出終端,最覺的輸出終端有console與file了,另外還有其它如GUI components, JMS, NT Event Loggers, remote socket servers等等。
Appender也有類似繼承的原則,即當前logger的appender包括其它父類的appender。這樣就會出現一個logger可能擁有多個appender了,在現實中看來,就是log4j的日志信息可以同進輸出到console, file等等終端了。當然,為了不使此appender惡性疊加,可以通過設置additivity標志來阻止繼承。
規則-若當前logger為C,則C擁有包括其自己及其父類的所有appender。另外,若C的父logger為P,且P的additivity標志已經設置成為false,則C只擁有自己及P的appender了,而P則只能擁有本身的appender。
以下表格可以清晰說明此規則:
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 . |
對于layout,也正如前面所述,是用來定義日志信息的輸出格式,它的與C語言中printf
函數的格式定義基本相似,本人對printf中的格式參數不太熟悉,總感覺有些復雜,一般是平時看到自己認為有用的格式就記一下,到時直接搬過來。如
log4j.appender.R.layout.ConversionPattern=--->%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n
時,日志信息格式為:
--->2008-07-11 01:13:40 [ INFO]com.test.Log4jTest.main(Log4jTest.java:27) - Exiting application.
好啦,現在log4j的理論很膚淺地扯了一下,現在可以開始配置了。
配置:
Log4j的配置可以通過加載Java的properties配置文件或者XML文件來完成。
Log4j默認的配置為,通過讀取系統變量log4j.configuration來找到配置文件,當然變量的默認值為log4j.properties,所以若沒有設置此系統變量,可以直接將配置文件命名為log4j.properties,然后放到類路徑下即可。另外,若想引用通過其它配置文件,則可以通過
Loader.getResource(java.lang.String)來讀取指定的配置文件。
其它:
1. 由于有了log4j中的級別繼承機制,所以可以很方便地過濾信息了,不僅可以很方便地限制日志的輸出量,也可以同時將日志輸出到不同的終端。
另外,因為在java文件中,文件的物理層次關系也是直接通過“.”符號來控制的,且在很在程度上這個物理層次也決定了文件的邏輯層次,所以我們在當前文件中獲取logger時,可以直接通過當前文件的類名來獲取,如:
static Logger logger = Logger.getLogger(MyApp.class);
這樣,在過濾消息時就很簡單了,簡單示例如下:
在配置文件中有
log4j.rootLogger=ERROR,stdout,R
log4j.category.com.db=DEBUG
log4j.category.com.i18n=INFO
log4j.category.com.zyx=fatal
默認的root logger的日志級別為Error,根據級別關系這個級別也相當高了,這樣可以減少系統中日志的輸出量,但有些地方可能得輸出更詳細信息,如數據庫部分,所以可以將com.db設置成了debug。另外,我在com.zyx下,我只想看到類型為fatal的日志,也可以如上所設。
2. log4j.rootLogger=ERROR,stdout, ROLLING_FILE這個定義表示root logger的日志級別為Error,后面的stdout, ROLLING_FILE表示此root有二個appender,通??梢酝ㄟ^這樣來定義日志可以同時向多個終端輸出,因為子logger可以繼承所有父logger的appender.
如我可以通過以下定義將日志同時往console及file輸出:
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=--->%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.File=myapp.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=1024KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=10
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern==[slf5s.start]%d{DATE}[slf5s.DATE]%n"
%p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n"
%c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n
|
馬馬虎虎總結了一下,但也花費了二個多小時,呵呵!