The Apache Software Foundation(以降,ASF)にLogging Servicesというプロジェクトが発足したのをご存知だろうか。

 このプロジェクトの目的は,その名の通りログ・サービスを行うプロダクトの開発を行うことだ。ASF内には,今までもJakarta ProjectではLog4jというログ・サービス・プロダクトが,Avalon ProjectではLogkitというロギング・フレームワークが開発されていた。また,ASF以外にも様々な言語や環境用のログ・サービス・プロダクトがオープンソースとして開発されていた。

 Logging Servicesプロジェクトは,言語ごとに開発されていたプロダクトを1つのプロジェクトで集中管理し,言語を跨ったログ・サービスを提供することを目的としている。その一環として,Jakarta Projectで開発されていたJava言語用のログ・サービスLog4jは,2003年12月に発足したこの,Logging Servicesプロジェクトに移動した。この他,Logging Servicesプロジェクトには,C++用のLog4cxx,.NET用のLog4net,php用のLog4phpがそれぞれ開発されている。それぞれのプロダクトは2004年1月に発足したばかりであるが,今後が楽しみなプロダクトばかりである。

ロギング・フレームワークのデファクトLog4j

 Jakarta Projectで以前より開発が行われていたLog4jは,Javaアプリケーションに強力なログ出力機能を提供している。シンプルなAPIながら,柔軟にカスタマイズ可能な出力機能が支持され,多くのオープンソースプロダクトにて利用されている。まずは,リスト1をご覧いただきたい。


リスト●Log4jを利用したログ出力プログラム例

  Logger logger = Logger.getLogger("sample");

  logger.debug("This is sample log message");
 ログ出力を行うためのプログラム記述はこれだけである。クラスLoggerのオブジェクトを入手し,ログ・レベルに合わせたメソッドを呼び出すだけだ。Log4jは標準では5つのログ・レベルが用意されている。深刻なほうから,fatal,error,warn,info,debugである。それぞれは,設定ファイルによって出力するログ・レベルの調節が可能だ。開発時には,すべてを出力,運用時にはワーニング以上を出力といった制御が可能であり,ログ出力の可否を判定するif文をログ出力文の前に記述する必要はない。また,出力可否判定や,実際の出力処理に対するパフォーマンスも考慮されており,安心して利用していただきたい。

図1●カテゴリの概念図
 特に,開発時に行いがちなのが,System.out.println によるデバッグ文の記述だが,System...によるデバッグ文は,パフォーマンスやログ収集に深刻な影響を与えるため,プログラム完成時には動作しないよう,制御文で囲むか削除しなくてはならない。しかし,随所に挿入したSystem...文を削除する作業は,消し忘れや作業ミスを発生しかねない。そのようなことがないよう,コーディング当初からLog4jを利用すればよいのである。開発中にログファイを参照する作業を煩わしいと感じるなら,出力先を標準出力にする事も可能なので,安心してほしい。

 前述のようにシンプルなAPIにて,ログ出力機能を提供するLog4jだが,カテゴリという概念を用いて,非常に強力な出力制御が行える。カテゴリとは,ログ出力文のグループのようなものと考えることができるだろう。同一のカテゴリに属するログ出力文は,同一の制御下にあることになる。Log4jでのログ出力の制御は,カテゴリに対して行うため,複数のログ出力文をかんたんに制御可能となる(図1[拡大表示])。

 また,カテゴリは継承の概念によって階層化されており,上位層の設定は下位のカテゴリに継承される。階層は,カテゴリ名にて決定される仕組みとなっている。カテゴリ名はログ出力を司るクラスLogger(Log4jバージョン1.2以前は,クラスCategory)入手時に指定した文字列で決定する。この時に指定する文字列をドット“.”で区切ることで階層を示すことになる。

図2●カテゴリの階層化概念図
 例えば,"a.b"と"a.c"というカテゴリのLoggerを入手した場合,両者は共にaというカテゴリにも属していることになる。Log4jではログ出力の制御指定は,カテゴリに対して行うため,aカテゴリに対しての出力制御は,a.bカテゴリおよび,a.cカテゴリに継承されることになる(図2[拡大表示])。カテゴリには,暗黙の親カテゴリROOTが存在し,すべてのカテゴリのルートとなっているため,全出力を制御したい場合には,ROOTカテゴリに対して制御を行えばよい。

 この,カテゴリの概念をうまく利用することで,アプリケーション内のログ出力をログレベル(ワーニングやデバッグなど)だけでなく,カテゴリでも制御できるようになる。例えば,カテゴリの命名を完全修飾クラス名で管理した場合。「特定のパッケージに対してのログ出力レベルを変更する」といったことが,アプリケーションの再コンパイルなしに,設定ファイルの修正のみで行えるのである。

Log4jの様々なログ出力制御

 Log4jは,実に様々な出力制御が行える。設定は前述のように,カテゴリに対する定義となり,出力先の制御,出力フォーマットの制御,出力レベル制御などが行え,それぞれ,Appender,Layout,Categoryによって制御される。設定は,プロパティファイルもしくは,XMLファイルにて行う。どちらのフォーマットを利用しても,設定する内容に違いはないため,プロパティ・ファイル形式にて紹介する。

 出力の制御を行うためには,まずカテゴリにAppenderを定義する。

 リスト2では,ルートカテゴリに A1という名前をつけたAppenderを,sampleカテゴリにはA2というAppenderを定義している。そのとき,カテゴリに対する出力レベルも同時に指定する。出力先の定義は,出力先ごとに用意されているAppenderのクラスを,log4j.appender.Appender名にて定義する。例では,A1にはファイル出力用のAppenderを,A2にはコンソール出力用のAppenderを定義している。よって,sampleという名前のカテゴリに属するログ出力は,コンソールへ,それ以外のカテゴリのログはファイルに出力されることになる。出力フォーマットはlog4j.appender.Appender名.layoutで指定したLayoutクラスに対する指定にて制御する。


リスト2●Log4jの設定ファイル例

log4j.rootLogger=WARN,A1
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=d:/AppLog/logs/sample.log
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%-5p] %d{ISO8601} - %m%n

log4j.category.sample=DEBUG,A2
log4j.appender.A2=org.apache.log4j.ConsoleAppender
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d %p %m%n
 この他にもUnixのsyslog,JMS(Java Messaging Service),Windows NTのイベントログ,SMTPへ出力するAppenderや,HTML出力フォーマットを提供するLayoutなどが用意されている。さらに,オリジナルのAppenderやLayoutを用意する事も可能だ。

 Logging Servicesプロジェクトは,前述のようにLog4j以外にもログ出力プロダクトが開発されている。それぞれ,Log4jの思想をベースに各言語用のプロダクトを作成しており,基本的な概念はLog4jと同様となっているようだ。ログ出力を行う必要のアプリケーションを作成する場合は,それぞれの言語用のプロダクトの利用を検討してみてはいかがだろうか。

黒住幸光(Kurozumi Yukimitsu)

■著者紹介
黒住幸光(くろずみ ゆきみつ)氏
株式会社アークシステム シニアコンサルタント。1989年,スーパー・コンピュータ向け言語処理環境の研究中に,生まれて間もないJavaと出会い,Javaに専念するため転職を決意。現在,株式会社アークシステムにてオープンソース・ソフトウエアを用いたWWWシステムの構築,コンサルティングを行うかたわら,雑誌への執筆,StrutsユーザーMLの管理,Ja-JakartaプロジェクトTurbine翻訳の取りまとめなど幅広く活動中。メール・アドレスは,yukimi_2@yahooo.co.jp