Jakarta Log4j
入手
dist/lib/log4j-?.?.?.jarをクラスパス上に置く。
ログレベル
レベルの低い順に、DEBUG, INFO, WARN, ERROR, FATALとなっている。
基本的な分類
| ログレベル | 用途 |
|---|---|
| DEBUG | デバッグ情報 |
| INFO | 運用情報 |
| WARN | 警告情報 |
| ERROR | エラー情報 |
| FATAL | 致命的な情報 |
実装
import org.apache.log4j.Logger;
public class Log4jSample {
public static void main(String[] args) {
Log4jSample logic = new Log4jSample();
logic.method();
}
public void method(){
Logger logger = Logger.getLogger(this.getClass());
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
logger.fatal("fatal");
}
}
システムのログレベルがINFOのときは、INFOよりレベルの低いDEBUGのロギング処理がスキップされる。INFOを含んだINFOより高いレベルのロギング処理が実行される。
ログレベルの変更を定義ファイルやSystemプロパティなどで手軽に行うことができるため、開発環境ではDEBUG、運用環境ではINFOのような使い分けを行うことができる。
ログレベル、出力フォーマットなどの指定
構成
Log4jは次の3つの要素で構成されている。
- Categories
- Appenders
- Layouts
Categories
複数のロギング設定をカテゴリとして分類することができる。
カテゴリの分類には、javaのパッケージが利用される。
Appenders
ログ出力のあて先を指定する。
あて先とは、コンソール・ファイル・GUIコンポーネントなどを表す。
複数のあて先を指定した場合、非同期でロギング処理が実行される。
Layouts
出力時のレイアウトを指定する。TEXT,HTML,XMLなど。
log4j.properties
Categories
プロパティファイルでカテゴリーの指定を行う場合、次のような書式で行う。
log4j.rootLogger=[レベル], [Appender] log4j.logger.package.package=[レベル], [Appender] log4j.logger.com.ayumu-baby.634.logic=[レベル], [Appender]
全てのパッケージに対する設定
log4j.rootLogger=[レベル], [Appender]
上記のように指定することで、すべてのパッケージに対してログの設定を行うことができる。
個別のパッケージに対する設定
log4j.logger.[パッケージ階層]
パッケージを指定することで、指定したパッケージに対するログの設定を行うことができる。
なお、親パッケージの設定は子パッケージでも有効となる。
親子ともにカテゴリ設定が行われている場合、子の設定が優先される。
Appenders
log4j.appender.[Appender名]=[Appenderクラス]
Log4jプロジェクトで用意されているAppenderにはAsyncAppender, JMSAppender, NTEventLogAppender, NullAppender, SMTPAppender, SocketAppender, SyslogAppender, WriterAppenderがある。
たとえばWriteAppenderのサブクラスであるConsoleAppenderをstandardという名称のAppenderとして指定するためには
log4j.appender.standard=org.apache.log4j.ConsoleAppender
とする。
Layouts
log4j.appender.[Appender名].layout=[Layoutクラス]
Log4jプロジェクトで用意されているLayoutには、DateLayout, HTMLLayout, PatternLayout, SimpleLayout, XMLLayoutがある。
プロパティファイルの例
Log4j.properties
log4j.rootLogger=INFO,standard log4j.logger.logic=DEBUG,standard log4j.logger.web=DEBUG,standard,io log4j.appender.standard=org.apache.log4j.ConsoleAppender log4j.appender.standard.layout=org.apache.log4j.SimpleLayout log4j.appender.io=org.apache.log4j.FileAppender log4j.appender.io.File=log.html log4j.appender.io.layout=org.apache.log4j.HTMLLayout
- logicパッケージ内のログメッセージはコンソールに出力される。
- webパッケージ内のログメッセージはコンソールとファイル(log.html)に出力される。
- 上記以外のパッケージ内のログメッセージはコンソールに出力される。
XML定義ファイル
枠組み
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "./log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> </log4j:configuration>
Category
カテゴリーの指定はCategoryタグを使用する。タグの内側に参照するAppenderを記述する。
<category name="log4j">
<appender-ref ref="CONSOLE_INFO" />
<appender-ref ref="LOGFILE_DEBUG" />
</category>
<root>
<appender-ref ref="CONSOLE_INFO" />
</root>
Appender&Layouts
AppenderとLayoutsはセットで定義する。
<appender name="CONSOLE_INFO" class="org.apache.log4j.ConsoleAppender" >
<param name="threshold" value="info"/>
</appender>
<appender name="LOGFILE_DEBUG" class="org.apache.log4j.FileAppender">
<param name="threshold" value="debug"/>
<param name="file" value="debug.html" />
<param name="append" value="true" />
<layout class="org.apache.log4j.HTMLLayout"/>
</appender>
Layoutに書式をパラメータで渡す場合、Layoutタグの中に<param>タグで指定する。
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d %-5p %c - %m [%t] (%F:%L)%n" />
</layout>
XML定義ファイルの例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "./log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="CONSOLE_INFO" class="org.apache.log4j.ConsoleAppender" >
<param name="threshold" value="info"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d (%F:%L) %m%n"/>
</layout>
</appender>
<appender name="LOGFILE_DEBUG" class="org.apache.log4j.FileAppender">
<param name="threshold" value="debug"/>
<param name="file" value="debug.html" />
<param name="append" value="true" />
<layout class="org.apache.log4j.HTMLLayout"/>
</appender>
<category name="log4j">
<appender-ref ref="LOGFILE_DEBUG" />
</category>
<root>
<appender-ref ref="CONSOLE_INFO" />
</root>
</log4j:configuration>
Java/log4j/Nested Diagnostic Context(NDC)
NDCの概要
Log4jで用意されているオブジェクト。
このオブジェクトに値を設定しておくことで、ログ出力時にその設定した値を出力することができる。
で、何がうれしいのかというと、NDCはThreadLocalなので、スレッドごとに別の値を保有できるということ。
説明が難しいのでたとえば、
log.debug("log2");
というLog4jのコードがあって、それをユーザーAさんが実行した。
ログの内容
2009/12/01 10:11:12 log2
続いてユーザーBさんが実行。
ログの内容
2009/12/01 10:11:12 log2
2009/12/01 10:11:15 log1
2009/12/01 10:11:15 log2
さて、これだと誰の実行ログなのかわからないので、
「ログにユーザーIDを出してください」
といわれたとする。
単純にやると、
log.debug(userId + ":log2");
システムが単純ならいいんだけど、これが「一時的に」とか「大規模システム全体」にとかなると、きつい。
将来的に、「ユーザーの所属グループも出してくれ」とか言われたら、また繰り返し。
これを解決するのがNDC。Log4jってすばらしい。
使い方
ロギングを行う前に、NDCオブジェクトに値を設定しておく。
フィルターで使うことが多いんじゃないかと思う。
設定した値は%xで出力指定する。
コード
ソースファイル(抜粋)
log.debug("log1");
log.debug("log2");
NDC.remove();
log4j.properties(例)
#console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%x %-5p %d{HH:mm:ss} %m%n
結果
hello DEBUG 10:05:25 log2
ナイス!
プッシュした分だけ、
NDC.push("hello");
log.debug("log1");
log.debug("log2");
NDC.remove();
NDC.remove();
%xで表示される
hello hello DEBUG 10:05:25 log2
ユーザーごとに(正確にはスレッドごとに)値を設定すれば、
log.debug("log1");
log.debug("log2");
NDC.remove();
ちゃんと追跡できる
userA DEBUG 10:05:25 log2
userZ DEBUG 10:31:10 log1
userZ DEBUG 10:31:10 log2
設定した値の開放
設定した値は NDC.remove();で開放しないとずっと保持されたままになってしまうので、ちゃんと開放すること!
try-finallyか、destroy系の処理内で書くのがベスト。
まとめ
横槍通す感じだからアスペクト指向に似てる。
フィルターで使えば取り外しも簡単。

