# 5 `logging` -- Python 用ロギング機能

バージョン 2.3 で 新たに追加 された仕様です。 このモジュールでは、アプリケーションのための柔軟なエラーログ記録 (logging) システムを実装するための関数やクラスを定義しています。

ログ記録は `Logger` クラスのインスタンス (以降 ロガー :logger) におけるメソッドを呼び出すことで行われます。各インスタンスは 名前をもち、ドット (ピリオド) を区切り文字として表記することで、 概念的には名前空間中の階層構造に配置されることになります。 例えば、"scan" と名づけられたロガーは "scan.text"、"scan.html"、 および "scan.pdf" ロガーの親ロガーとなります。ロガー名には何をつけてもよく、 ログに記録されるメッセージの生成元となるアプリケーション中の特定の 領域を示すことになります。

ログ記録されたメッセージにはまた、重要度レベル (level of importance) が関連付けられています。デフォルトのレベルとして提供されているものは `DEBUG`、`INFO`、`WARNING`、 `ERROR` および `CRITICAL` です。簡便性のために、 `Logger` の適切なメソッド群を呼ぶことで、ログに記録されたメッセージの 重要性を指定することができます。それらのメソッドとは、デフォルトの レベルを反映する形で、`debug()`、 `info()`、 `warning()`、 `error()` および `critical()` となっています。 これらのレベルを指定するにあたって制限はありません: `Logger` の より汎用的なメソッドで、明示的なレベル指定のための引数を持つ `log()` を使って自分自身でレベルを定義したり使用したりできます。

ログレベルの数値は以下の表のように与えられています。 これらは基本的に自分でレベルを定義したい人のためのもので、 定義するレベルを既存のレベルの間に位置づけるために具体的な値が必要になります。 もし数値が他のレベルと同じだったら、既存の値は上書きされその名前は失われます。

レベル | 数値
--- | ---
`CRITICAL` | 50
`ERROR` | 40
`WARNING` | 30
`INFO` | 20
`DEBUG` | 10
`NOTSET` | 0

レベルもロガーに関連付けることができ、デベロッパが設定することも、 保存されたログ記録設定を読み込む際に設定することもできます。 ロガーに対してログ記録メソッドが呼び出されると、ロガーは自らの レベルとメソッド呼び出しに関連付けられたレベルを比較します。 ロガーのレベルがメソッド呼び出しのレベルよりも高い場合、実際の ログメッセージは生成されません。これはログ出力の冗長性を制御 するための基本的なメカニズムです。

ログ記録されるメッセージは `LogRecord` クラスのインスタンスとして コード化されます。ロガーがあるイベントを実際にログ出力すると決定した 場合、ログメッセージから `LogRecord` インスタンスが生成されます。

ログ記録されるメッセージは、ハンドラ (handlers) を通して、 処理機構 (dispatch mechanism) にかけられます。ハンドラは `Handler` クラスのサブクラスのインスタンスで、ログ記録された (`LogRecord` 形式の) メッセージが、そのメッセージの伝達対象となる相手 (エンドユーザ、サポートデスクのスタッフ、システム管理者、開発者) に行き着くようにする役割を持ちます。ハンドラには特定の行き先に方向付け られた `LogRecord` インスタンスが渡されます。各ロガーは ゼロ個、単一またはそれ以上のハンドラを (`Logger` の `addHandler()` メソッド) で関連付けることができます。 ロガーに直接関連付けられたハンドラに加えて、 ロガーの上位にあるロガー全てに関連付けられたハンドラ がメッセージを処理する際に呼び出されます。

ロガーと同様に、ハンドラは関連付けられたレベルを持つことができます。 ハンドラのレベルはロガーのレベルと同じ方法で、フィルタとして働きます。 ハンドラがあるイベントを実際に処理すると決定した場合、 `emit()` メソッドが使われ、メッセージを発送先に送信します。ほとんどの ユーザ定義の `Handler` のサブクラスで、この `emit()` をオーバライドする必要があるでしょう。

基底クラスとなる `Handler` クラスに加えて、多くの有用なサブクラスが 提供されています:

1. `StreamHandler` のインスタンスはストリーム (ファイル様 オブジェクト) にエラーメッセージを送信します。

2. `FileHandler` のインスタンスはディスク上のファイルに エラーメッセージを送信します。

3. `BaseRotatingHandler` はログファイルをある時点で交替させる ハンドラの基底クラスです。直接インスタンス化するためのクラスではありません。 `RotatingFileHandler` や`TimedRotatingFileHandler` を使う ようにしてください。

4. `RotatingFileHandler` のインスタンスは最大ログファイルの サイズ指定とログファイルの交替機能をサポートしながら、ディスク上のファイルに エラーメッセージを送信します。

5. `TimedRotatingFileHandler` のインスタンスは、ログファイルを 一定時間間隔ごとに交替しながら、ディスク上のファイルに エラーメッセージを送信します。

6. `SocketHandler` のインスタンスは TCP/IP ソケットにエラーメッセージを送信します。

7. `DatagramHandler` のインスタンスは UDP ソケットにエラーメッセージを送信します。

8. `SMTPHandler` のインスタンスは指定された電子メールアドレスにエラーメッセージを送信します。

9. `SysLogHandler` のインスタンスは遠隔を含むマシン上の syslog デーモンにエラーメッセージを送信します。

10. `NTEventLogHandler` のインスタンスは Windows NT/2000/XP イベントログにエラーメッセージを送信します。

11. `MemoryHandler` のインスタンスはメモリ上のバッファにエラーメッセージを送信し、指定された条件でフラッシュされるようにします。

12. `HTTPHandler` のインスタンスは "`GET`" か "`POST`"セマンティクスを使って HTTP サーバにエラーメッセージを送信します。

`StreamHandler` および `FileHandler` クラスは、中核となる ログ化機構パッケージ内で定義されています。他のハンドラはサブモジュール、 `logging.handlers` で定義されています。 (サブモジュールには もうひとつ `logging.config` があり、これは環境設定機能の ためのものです。)

ログ記録されたメッセージは `Formatter` クラスのインスタンスを 介し、表示用に書式化されます。これらのインスタンスは % 演算子と辞書を 使うのに適した書式化文字列で初期化されます。

複数のメッセージの初期化をバッチ処理するために、 `BufferingFormatter` のインスタンスを使うことができます。 書式化文字列 (バッチ処理で各メッセージに適用されます) に加えて、 ヘッダ (header) およびトレイラ (trailer) 書式化文字列が用意されて います。

ロガーレベル、ハンドラレベルの両方または片方に基づいたフィルタリング が十分でない場合、`Logger` および `Handler` インスタンスに `Filter` のインスタンスを (`addFilter()` メソッドを介して) 追加することができます。メッセージの処理を進める前に、ロガーとハンドラは ともに、全てのフィルタでメッセージの処理が許可されているか調べます。 いずれかのフィルタが偽となる値を返した場合、メッセージの処理は 行われません。

基本的な `Filter` 機能では、指定されたロガー名でフィルタを 行えるようになっています。この機能が利用された場合、名前付けされた ロガーとその下位にあるロガーに送られたメッセージがフィルタを通過 できるようになり、その他のメッセージは捨てられます。

上で述べたクラスに加えて、いくつかのモジュールレベルの関数が存在します。

`getLogger`( | [name])

  指定された名前のロガーを返します。名前が指定されていない場合、 ロガー階層のルート (root) にあるロガーを返します。 name を指定する場合には、通常は "a", "a.b", あるいは "a.b.c.d" といったようなドット区切りの階層的な 名前にします。名前の付け方はログ機能を使う開発者次第です。

  与えられた名前に対して、この関数はどの呼び出しでも同じロガーインスタンス を返します。従って、ロガーインスタンスをアプリケーションの各部 でやりとりする必要はなくなります。

`getLoggerClass`( | )

  標準の`Logger` クラスか、最後に`setLoggerClass()` に渡した クラスを返します。この関数は、新たに定義するクラス内で呼び出し、 カスタマイズした`Logger` クラスのインストールを行うときに 既に他のコードで適用したカスタマイズを取り消そうとしていないか 確かめるのに使います。例えば以下のようにします:

       class MyLogger(logging.getLoggerClass()):
           # ... override behaviour here

`debug`( | msg[, *args[, **kwargs]])

  レベル `DEBUG` のメッセージをルートロガーで記録します。 msg はメッセージの書式化文字列で、args は msg に 文字列書式化演算子を使って取り込むための引数です。(これは、 書式化文字列でキーワードを使い引数に辞書を渡すことができる、ということを意味します。)

  キーワード引数 kwargs からは二つのキーワードが調べられます。 一つめは exc_info で、この値の評価値が偽でない場合、 例外情報をログメッセージに追加します。(`sys.exc_info` の返す形式の) 例外情報を表すタプルが与えられていれば、それを メッセージに使います。それ以外の場合には、`sys.exc_info` を呼び出して例外情報を取得します。

  もう一つのキーワード引数は extra で、当該ログイベント用に作られた LogRecoed の __dict__ にユーザー定義属性を増やすのに使われる辞書を渡すのに 用いられます。これらの属性は好きなように使えます。たとえば、ログメッセージの一部に することもできます。以下の例を見てください:

       FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
       logging.basicConfig(format=FORMAT)
       d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
       logging.warning("Protocol problem: %s", "connection reset", extra=d)

  出力はこのようになります。

      2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset

  extra で渡される辞書のキーはロギングシステムで使われているものとぶつからない ようにしなければなりません。(どのキーがロギングシステムで使われているかについての 詳細は `Formatter` のドキュメントを参照してください。)

  これらの属性をログメッセージに使うことにしたなら、少し注意が必要です。 上の例では、'clientip' と 'user' が LogRecord の属性辞書に含まれている ことを期待した書式化文字列で `Formatter` はセットアップされてい ます。これらの属性が欠けていると、書式化例外が発生してしまうためメッセー ジはログに残りません。したがってこの場合、常にこれらのキーがあ る extra 辞書を渡す必要があります。

  このようなことは煩わしいかもしれませんが、この機能は限定された場面で使 われるように意図しているものなのです。たとえば同じコードがいくつものコ ンテキストで実行されるマルチスレッドのサーバで、興味のある条件が現れる のがそのコンテキストに依存している(上の例で言えば、リモートのクライアン ト IP アドレスや認証されたユーザ名など)、というような場合です。そういっ た場面では、それ用の `Formatter` が特定の `Handler` と共に 使われるというのはよくあることです。

  バージョン 2.5 で 変更 された仕様: extra が追加されました

`info`( | msg[, *args[, **kwargs]])

  レベル `INFO` のメッセージをルートロガーで記録します。 引数は `debug()` と同じように解釈されます。

`warning`( | msg[, *args[, **kwargs]])

  レベル `WARNING` のメッセージをルートロガーで記録します。 引数は `debug()` と同じように解釈されます。

`error`( | msg[, *args[, **kwargs]])

  レベル `ERROR` のメッセージをルートロガーで記録します。 引数は `debug()` と同じように解釈されます。

`critical`( | msg[, *args[, **kwargs]])

  レベル `CRITICAL` のメッセージをルートロガーで記録します。 引数は `debug()` と同じように解釈されます。

`exception`( | msg[, *args])

  レベル `ERROR` のメッセージをルートロガーで記録します。 引数は `debug()` と同じように解釈されます。 例外情報はログメッセージに追加されます。このメソッドは 例外ハンドラからのみ呼び出されます。

`log`( | level, msg[, *args[, **kwargs]])

  レベル `level` のメッセージをルートロガーで記録します。 その他の引数は `debug()` と同じように解釈されます。

`disable`( | lvl)

  全てのロガーに対して、ロガー自体のレベルに優先するような上書きレベル lvl を与えます。アプリケーション全体にわたって一時的にログ出力の 頻度を押し下げる必要が生じた場合にはこの関数が有効です。

`addLevelName`( | lvl, levelName)

  内部辞書内でレベル lvl をテキスト levelName に関連付け ます。これは例えば `Formatter` でメッセージを書式化する 際のように、数字のレベルをテキスト表現に対応付ける際に用いられます。 この関数は自作のレベルを定義するために使うこともできます。 使われるレベル対する唯一の制限は、レベルは正の整数でなくては ならず、メッセージの深刻さが上がるに従ってレベルの数も上がらなくては ならないということです。

`getLevelName`( | lvl)

  ログ記録レベル lvl のテキスト表現を返します。レベルが定義 済みのレベル `CRITICAL`、`ERROR`、 `WARNING`、 `INFO`、あるいは `DEBUG` のいずれかである場合、対応する文字列が返されます。 `addLevelName()` を使ってレベルに名前を関連づけていた 場合、lvl に関連付けられていた名前が返されます。 定義済みのレベルに対応する数値を指定した場合、レベルに対応した 文字列表現を返します。そうでない場合、文字列 "Level %s" % lvl を 返します。

`makeLogRecord`( | attrdict)

  属性が attrdict で定義された、新たな `LogRecord` インスタンスを生成して返します。この関数は pickle 化された `LogRecord` 属性の辞書を作成し、ソケットを介して送信し、受信端で `LogRecord` インスタンスとして再構成する際に便利です。

`makeLogRecord`( | attrdict)

  attrdict で属性を定義した、新しい `LogRecord` インスタンスを 返します。この関数は、逆 pickle 化された `LogRecord` 属性辞書を socket 越しに受け取り、受信端で `LogRecord` インスタンスに再構築す る場合に有用です。

`basicConfig`( | [**kwargs])

  デフォルトの `Formatter` を持つ `StreamHandler` を生成してルートロガーに追加し、ログ記録システムの基本的な環境設定を 行います。 関数 `debug()`、`info()`、`warning()`、 `error()`、および `critical()` は、ルートロガーに ハンドラが定義されていない場合に自動的に `basicConfig()` を呼び出します。

  バージョン 2.4 で 変更 された仕様: 以前は `basicConfig` はキーワード引数を とりませんでした

  以下のキーワード引数がサポートされます。

  Format | 説明
  --- | ---
  `filename` | StreamHandler ではなく指定された名前で FileHandler が作られます
  `filemode` | filename が指定されているとき、ファイルモードを指定します (filemode が指定されない場合デフォルトは 'a' です)
  `format` | 指定された書式化文字列をハンドラで使います
  `datefmt` | 指定された日付/時刻の書式を使います
  `level` | ルートロガーのレベルを指定されたものにします
  `stream` | 指定されたストリームを StreamHandler の初期化に使います。 この引数は 'filename' と同時には使えないことに注意してください。 両方が指定されたときには 'stream' は無視されます

`shutdown`( | )

  ログ記録システムに対して、バッファのフラッシュを行い、全てのハンドラを 閉じることで順次シャットダウンを行うように告知します。

`setLoggerClass`( | klass)

  ログ記録システムに対して、ロガーをインスタンス化する際にクラス klass を使うように指示します。指定するクラスは引数として 名前だけをとるようなメソッド `__init__()` を定義して いなければならず、`__init__()` では `Logger.__init__()` を呼び出さなければなりません。典型的な利用法として、この関数は自作の ロガーを必要とするようなアプリケーションにおいて、他のロガーが インスタンス化される前にインスタンス化されます。

参考:

PEP 282, A Logging System
  本機能を Python 標準ライブラリに含めるよう記述している提案書。

この `logging` パッケージのオリジナル
  オリジナルの`logging`パッケージ。このサイトにあるバー ジョンのパッケージは、標準で`logging`パッケージを含まな いPython 1.5.2 と 2.1.x、2.2.xでも使用できます