Frequently Asked Questions about log4j

Ceki Gülcü
2000年12月


log4jとは?

log4jは、プログラマーがいろいろな出力宛先にログ文を出力するのを 手助けするツールです。

アプリケーションに関する問題の場合には、問題の場所が特定ができるように、 ログ記録することを可能にすることは、役に立ちます。 log4jは、バイナリのアプリケーションを修正することなく実行時に ログ記録を有効にすることが可能です。 log4jパッケージは、出荷したコードに対して、ログ文を残したままにし、 重たいパフォーマンスコストを負うことが無いように設計されました。 ログ記録する(またはしない)スピードが重要になります。

同時に、ログ出力は、それが速く起こるほど圧倒的に大量になります。 log4jの特徴的な機能のひとつは、階層的なカテゴリーの概念です。 選択的に可能であるカテゴリーを使うことで、どのログ文を 任意の粒度で出力するかを制御します。

log4jは、その考えには、2つの明確な目標で設計されています。 それは速度と柔軟性です。タイトなバランスがこの2つの必要条件 の間にあります。私は、log4jが正しくバランスを保つと信じています。

log4j は信頼できるロギングシステムなの?

いいえ。log4jは、reliableではありません。best-effortで fail-stopなロギングシステムです。

fail-stopは、我々はlog4jがあなたのアプリケーションを 実行時にクラッシュさせるような可能性のある、予想外の例外を 投げつけないという意味です。 どんな理由にせよ、log4jが捕捉できない例外を投げた場合には、 log4j-user@jakarta.apache.org メールを送ってください。 捕捉できない例外は、即時の注意を必要とするる重大なバグとして 扱われます。

さらに、その指定の出力ストリームが開けられないか、書くことができないか、 いっぱいになったとき、log4jはSystem.outまたはSystem.errに戻しません。 ログ記録の失敗によって、ユーザーの端末を氾濫させることで、 その他の点では問題なく働くプログラムを駄目にすることを避けます。 しかし、log4jはロギングの実行ができないことを 報告するためSystem.errに、一回だけメッセージを出力します。

log4に必要なものは何?

log4jのjavadocドキュメントはありますか?

javadoc
ドキュメンテーション は log4jパッケージの一部です。 説明マニュアルもあります。 問題があった場合には、log4j トラブルシューティング ドキュメントを見て確認してください。

その他のロギングパッケージは何があるの?

多くのロギングパッケージがあります。私が知っているのは、
Grace Software's JavaLog, JLog, Software ZOO's toolkit, SDSU logging package です。 このリストは完全に網羅してはいません。

log4jを使用したサンプルコードはありますか?

サンプルは org/log4j/examplesディレクトリに含まれています。また、 org/log4j/xml/examplesも参照してください。

log4jの機能は?

ログ出力はどのように見えますか?

ログ出力は、さまざまな方法でカスタマイズすることができます。 さらに、独自のレイアウトを実行することによって完全に 出力フォーマットをオーバーライドすることができます。

変換パターン "%r [%t] %-5p %c{2} %x - %m%n" PatternLayoutを使った出力例があります。

176 [main] INFO  examples.Sort - Populating an array of 2 elements in reverse order.
225 [main] INFO  examples.SortAlgo - Entered the sort method.
262 [main] DEBUG SortAlgo.OUTER i=1 - Outer loop.
276 [main] DEBUG SortAlgo.SWAP i=1 j=0 - Swapping intArray[0] = 1 and intArray[1] = 0
290 [main] DEBUG SortAlgo.OUTER i=0 - Outer loop.
304 [main] INFO  SortAlgo.DUMP - Dump of interger array:
317 [main] INFO  SortAlgo.DUMP - Element [0] = 0
331 [main] INFO  SortAlgo.DUMP - Element [1] = 1
343 [main] INFO  examples.Sort - The next log statement should be an error message.
346 [main] ERROR SortAlgo.DUMP - Tried to dump an uninitialized array.
        at org.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
        at org.log4j.examples.Sort.main(Sort.java:64)
467 [main] INFO  examples.Sort - Exiting main method.

最初のフィールドは、プログラムが開始してからの経過時間を ミリ秒単位ので表します。2番目のフィールドは、ログ文が出力して いるスレッドです。3番目のフィールドは、ログ文の優先度です。 4番目のフィールドは、ログ要求を作成したカテゴリーの右端の 2つの構成要素です。 5番目のフィールド(『-』だけの前に)は、nested diagnostic context(NDC)です。 ネスト化診断コンテキストが最初の2つの文の場合のように 空かもしれないので注意してください。 『-』の後のテキストは、ログ文のメッセージです。

Categoriesって何?

カテゴリーの概念が、log4jの中心にあります。 カテゴリーは、階層を定義して、プログラマーにどの文が印刷されるか、 実行時に制御を与えます。

カテゴリーは、優先度を割り当てられます。 ログ文は、その優先度そのカテゴリーに従い印刷されます。

詳細はlog4jマニュアル を必ず読むようにするようにしてください。

実行時にログの挙動を変更する方法は?

ログの挙動は、実行時に解析される設定ファイルを使用してセットすることができます。 設定ファイルを使用してプログラマーが定義したカテゴリーと優先度を設定 することができます。

PropertyConfiguratorは、設定ファイルの特定のフォーマットを定義します。 また、org.log4j.examples.Sort例と関連された構成ファイルを見てください。

設定ファイルは、XMLで指定することができます。 詳細はlog4j.dtdorg.log4j.xml.DOMConfiguratorを見てください。

特定の設定オプションについては、いろいろなLayoutとAppenderコンポーネント を参照してください。

設定ファイルに加えて、ユーザーは優先度のセットに属している全てのメッセージを 使用不能にするかもしれません。次の項目を見てください。

debug文とinfo文のための計算コストを下げる方法は?

あなたのコードの公開発表のために、BasicConfigurator.disable(pri)メソッドを呼ぶことは、 プライオリティーpriとそれ以下の全てのメッセージを使用不能にします。

アプリケーションに関する問題の場合、技術的なサポートは、クライアントのサイトで バイナリを変えることなくlog4j.disableOverrideシステム・プロパティを セットすることによってログ記録を再度有効にすることができます。

ログを記録する(しない)最速の方法は?

いくつかのカテゴリ catにおいて

  cat.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

と書いてある場合には、ログにメッセージが書かれるかどうかに かかわにず、

整数ientry[i]をStringに変換して、 中間文字列を連結してメッセージ・パラメータを構築するコストを負います。

速度が心配ならば、このように書きます。

   if(cat.isDebugEnabled()) {
     cat.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
   }

この方法は、CATカテゴリーのdebugが無効の場合には パラメータ構築のコストを負わずに済みます。一方、カテゴリーの debugが有効の場合に、カテゴリーが有効か無効かを2回評価する ことになります。一度はdebugEnabledで、もう一度は debugです。カテゴリーを評価することはそれが実際にログにかかる時間のおよそ 1%なので、これは微々たるオーバーヘッドです。

パラメータのうちの1つとしてString配列を 予期しているdebugメソッドの使用は、何ですか?

このメソッドは、もはや存在しません。そのかわりに Category.isDebugEnabled メソッドを使用してください。

なぜ、カテゴリー・クラスが導入されたのですか? そして、どのように、私は前のストリング・ベースの実装から移行すれば いいのですか?

理由は、速度、速度、速度です。

以前の実装では、カテゴリーがログ記録されるかどうかを評価するとき、 我々は潜在的にハッシュを計算して、各より高いランキング・カテゴリーのための一度、 倍数が時間を計る同等チェックをしました。 例えば、カテゴリー名が「x.y.z」であるならば、それがすでに定義される (同等にチェックを要しまして)ならば、我々は「x.y.z」のハッシュを計算して、 チェックしました。 もしそうでなければ、我々はそれが定義された(もう一つの同等にチェックを要しまして) かどうかに関係なく、その「x.y」がより高いランキングであったということを発見する 「x.y.z」がそれから「x.y」のハッシュを計算して、チェックしたことを解析しました。 その他有効なカテゴリーが見つけられた、あるいは、残される可能なカテゴリーが 無くなるまで。

長い文字列のための、ハッシュ計算と同等のためにチェックが 計算の高価な操作であることがわかります。

新しいカテゴリー・クラスは、以前の実装の柔軟性を保持しつつ 非常に非常により良いパフォーマンスを提供します。 私は、機能性を損なうことなくパフォーマンスが向上することができない ところまで行きたいと思います。 この思い込みを暴露するのをためらわないでください。 Alex Blewitt, F. Hoering and M. Oestreicher らの貢献は、これらのパフォーマンス改良に助けになりました。

カテゴリーを定義するための新文法は

  
  Category cat = Category.getInstance("x.y.z");
  cat.setPriority(Priority.DEBUG);

です。

以前と同じ効果をもつには

  log.setCategory("x.y.z", "DEBUG"); // ここでlogはLogのインスタンス

リリース0.8.0現在、ログ文(debug, info, ...メソッド)が log シングルトンをもはや必要としません。その代わりにCategoryインスタンスを使うように、 構文はさらに修正されました。

以前は、いくつかのクラス X は、こう記述しました

package a.b.c;

class X {
  static String cat = "a.b.c.X";

  void foo() {
    log.debug(cat, "Some foo message").
    ...
  }
}
このコードは次のように修正する必要があります。
package a.b.c;

import org.log4j.Category; 

class X {
  static Category cat = Category.getInstance("a.b.c.X");

  void foo() {
    cat.debug("Some foo message").
    ...
  }
}

カテゴリー名をつけるために、お薦めの方法はありますか?

はい。ここにあります。

あなたは、独自にカテゴリーに名をつけることができます。 クラスの完全修飾名と等しいカテゴリー名で、各クラスでカテゴリーをインスタンス化 することはカテゴリーを定義する役に立つ直接の方法であることがわかります。 この方法は、多くの利点を持ちます:

しかし、これはカテゴリーに名をつけるための唯一の方法ではありません。 共通の選択肢は、機能範囲によってカテゴリーに名をつけることです。 例えば、「database」カテゴリー、「RMI」カテゴリー、「security」カテゴリーまたは「XML」カテゴリー。

あなたは機能によってカテゴリーに名をつけるほうを選ぶかもしれません。 そして、「DATABASE.com.ibm.some.package.someClass」または 「DATABASE.com.ibm.some.other.package.someOtherClass」の場合のように、 独自にサブカテゴリー分けできます。

あなたは、どのようなカテゴリー名を選ぶかは全く自由です。 log4jパッケージは、単に階層においてあなたの名前を管理するためにあなたを許すだけです。 しかし、この階層を定義することは、あなたの責任です。

場所によってカテゴリーに名をつけることによる注意は、 ほとんどの場合、独自性が密接に機能に関連があるので、 機能によってものに名をつける傾向があります。

staticブロックでクラスの完全修飾名を取得する方法は?

X.class.getName()文で、あなたはクラスXのためにstatic ブロックにおいて簡単にクラスの完全修飾名を取り出すことができます。 Xはクラス名で、インスタンスでないことに注意してください。 X.class文は、クラスXの新しいインスタンスを つくりません

テンプレート使用した説明があります:

package a.b.c;

public class Foo {
  static Category cat = Category.getInstance(Foo.class.getName());
  ... other code

}

log出力フォーマットをカスタマイズできますか?

はい。リリース0.7.0から、Layout クラスを独自にカスタマイズして作成したログフォーマットクラスに拡張できます。 appendersは、あなたの選択したレイアウトを使用してパラメータ化することができます。

複数のクライアント要求の出力は、異なるログ・ファイルへ行くことができますか?

多くの開発者は、異なるクライアント要求以外の同じクラスから始まっている ログ出力を識別する問題に直面しています。 彼らは、異なるファイルにログ出力を扇形に広げるために巧妙な仕組みを考え出します。 ほとんどの場合、これは正しい方法ではありません。

ネスト化診断コンテキスト(NDC)を使うことは、より単純です。 一般的に、NDC.push()で、クライアントの具体的な情報 (例えばクライアントのホスト名、IDまたはクライアントが 開始したときの要求で他と区別がつく情報など)をします。 その後は、あなたがログと異なるクライアント要求を見分けることができるように、 たとえ彼らが同じファイルへの出力であるとしても、 ログ出力は自動的にネスト化診断コンテキスト(NDC)を含みます。

詳細はNDCPatternLayoutクラスを見てください。 たとえ彼らが同じログ・ファイルを共有するとしても、 NumberCruncher例はNDCが使われることができる方法がログ出力と複数のクライアントを区別することを示します。

あるアプリケーション(例えば仮想ホスティングしているwebサーバー)に対して、 NDCソリューションは、十分ではありません。 バージョン0.9.0現在、log4jは複数の階層木をサポートします。 このように、それは現在のコンテキストに従い同じカテゴリーから異なる宛先までログが可能です。

Category インスタンスは作成されるだけのようです。 categoryインスタンスを削除するためのメソッドが無いのはなぜですか?

ユーザーによってさらにリファレンスをつけられる 「削除された」カテゴリーの意味論を定義することは、全くnon-trivialです。

将来のリリースではCategoryクラスに 削除メソッドが含まれるかもしれません

優先度によって異なる appendersにログ出力を向けることは、可能ですか?

はい出来ます。 AppenderSkeleton を拡張しているどんなappenderにもThresholdオプションをセットします。 lower優先度で全てのログ・イベントをフィルターするために (大部分のlog4j appendersは、AppenderSkeletonを拡張します) 閾値の値をオプションで設定します。

例えば、appenderの閾値にDEBUGの閾値を設定すれば、INFO, WARN, ERROR, FATALメッセージもまた許可されます(DEBUGは一番低い優先度です)。 これはDEBUGメッセージをINFO, WARN, ERROR, FATALメッセージで囲まれる ことがないときに通常うけいれられます。同様に、appenderの閾値に ERRORを設定すると、DEBUG, INFO, ERRORメッセージはフィルターされますが、 FATALメッセージはフィルターされません。

この方針は、通常最もユーザーが実際に、 考え-計画されたソリューションに対して、して欲しいものをカプセル化します。

sort4.lcf に閾値設定の例があるので参照しくてださい。

あなたが正確な優先度に一致したイベントにフィルターをかけなければならないならば、 あなたは正確な優先度に一致でイベントを記録することをフィルータするために PriorityMatchFilter をどんなappenderにでも付けることができます。

複数プロセスのログを同一ファイルに書き出すことはできますか?

それぞれのプロセスのログを SocketAppender. に送ります。 受信は SocketServer (または SimpleSocketServer) で行えば、すべてのイベントは、単一のログファイルに送ることができます。

たくさんのプロセスが複数のホストから(複数のタイムゾーンをまたがって) しるときに、上記の方法で同一ファイルに書くときにタイムスタンプはどうなるの?

タイムスタンプは、ログイベントが作成されたときに付けられます。 つまり、 debug, info, warn, error or fatal メソッドが呼ばれたときです。 リモートソケットサーバーへの到着によって時間が揺らが無いようにするためです。 タイムスタンプは、UTC形式でイベント内部に格納されています。 それらは、ホストのログファイルに書き出されるときに現れます。 いろいろなマシンでの時間が同期していないような場合には、 それぞれのホストでイベントが生成されたときに時間が狂います。

これは意図した挙動ですが、バージョン1.0.4と1.1b1の間でだけ最近 バグが発見されました。パージョン1.0.4以前では、コンバータでタイムスタンプ が生成されていました。この場合タイムスタンプは、ログサーバーホストの ローカル時間に従って到着したときに生成された順番で現れます。

なぜ、私はlog4jプロジェクトへ私の拡張を寄付しなければなりませんか?

GNU Public License (GPL) とは逆に、Apache Public Licenseは、 あなたの拡張についていかなる要求もしません。 あなたは、あなたの所有者のlog4j拡張を あなたが望むものは何にでもして結構です。 特に、あなたはより広い社会に決して あなたの拡張をリリースしないほうを選ぶかもしれません。

より新しいlog4jリリースが前のバージョンと後方互換を保つように、 我々はlog4jクライアントAPIを変えないように非常に注意します。 我々は、より内部のlog4j APIでだいぶ良心的ではありません。 このように、あなたの拡張がlog4jバージョンnで 働くようにできているならば、それから、log4jリリース・バージョン n+1が出るとき、あなたは多分あなたの所有者の拡張を 新しいリリースに適応させる必要があるでしょう。 このように、あなたはlog4j変更についていくために 貴重なリソースを費やすことを強制されます。 これは、一般に「ばかげた税金」と呼ばれます。 コードを贈与して、それを標準の配布の一部とすることで、 あなたはあなた自身に不必要な保守の仕事から解放されます。

あなたの拡張が役に立つならば、結局は、誰かが同じであるか非常に類似した 機能を提供するような拡張を書きます。 あなたの開発苦労は、無駄になります。

所有者のlog4j拡張が重大なビジネスでない限り、 あなたの拡張を贈与しないことのほとんど理由がプロジェクトへはありません。

コードを貢献するときに気をつけなければならないことは?

  1. たとえあなたが、気に入らなくても、現在のインデント形式を保持してください。

    複数のインデント形式を行き来するのは、ソースコードを理解不能にします。 あなた自身大変でも他のひとにはより簡単にしてください。 Log4jは、Code Conventions for the JavaTM Programming Languageに従っています。

  2. JDK 1.1 APIをサポートするために、あらゆる努力をしてください。

    og4jの重要な利点のうちの1つは、JDK 1.1.xとのその互換性です。

  3. あなたのコードを通しでテストしてください。

    コードをデバックする(つまりロギングする)ときに、 なにも腹立たしいバグが見つからないこと。

  4. 「シンプルで、小さく、高速に」を維持してください。

    ロギングは、アプリケーションの全てではありません。

  5. 関連するファイルの最上位の貢献者としてあなた自身を確認してください。

  6. あなたのコードに責任を持ってください。

    ソフトウェアを書くことは、育児のようです。 子供を育てるためには何年もかかります。

  7. 私は、インデント形式に固執することに言及しましたか?

どれくらい速く、log4jでのバグは、修正されますか?

次のリリースが準備ができているのを待つよりはむしろ、 我々はできるだけ早くバグ・フィックスをドアから取り出します。 さらに、一旦バグが見つけられるか、報告されるならば、それは家が火事とみなされます。 バグが修正されるまで、全ての他の活動は止まります。

従って、確認されたバグは、最初のバグ報告に続いて短期間で修正されます。

log4jの歴史は?

log4jの最初の祖先は、
SEMPER プロジェクトのために 書かれたものでした。 Jose-Luis Abad-Peiro が、最初の30のライナー版を書き、 Ceki Gülcü によって選択され、Andreas Fleuti によって強化されました。 Michael Steiner, N. Asokan, Ceki Gülcü は、 カテゴリー/優先度ベースを提案して、残りの概念は 同じく1996年から評価されました。

バグ報告の方法は?

バグ報告には
Apache Bug Databaseを 使用してください。

あなたの使用しているlog4jのバージョンを記述してください。 もしあれば、ログ設定ファイルとソースコードが含んであれば 参考になります。問題を再現する短いサンプルは、非常にありがたいです。

log4jの最新版の配布はどこからみつけられるの?

log4jプロジェクトは http://jakarta.apache.org/log4j/ にあります。


[訳注: これは熊坂祐二が翻訳しました。 日本語訳に対するコメントは、jajakarta-report@nekoyanagi.com宛に送って下さい。]