logging – ステータス、エラー、その他の情報をログ出力する

目的:ステータス、エラー、その他の情報をログ出力する
利用できるバージョン:2.3

logging モジュールは、アプリケーションやライブラリからのエラーやステータスといった情報をログ出力する標準の API を定義します。標準ライブラリモジュールがログ出力の API を提供する主な利点は、全ての Python モジュールが logging を使用するので、サードパーティモジュールからのメッセージをアプリケーションのログに含められます。

アプリケーションのログ出力

ログを精査するために2つの視点があります。アプリケーションの開発者は、 logging モジュールを設定して、適切な出力チャンネルへメッセージを出力します。これは異なる冗長レベルを用いたり、別の出力先へログメッセージを出力したりします。ログメッセージを書き込む、ファイル、HTTP GET/POST の場所、SMTP 経由のメール、汎用的なソケット、OS に特化したログの仕組みといったハンドラが全て含まれています。そして、そういった組み込みクラスでは扱えない特別な要件のためにカスタムログクラスを作成できます。

ファイルへのログ出力

ほとんどのアプリケーションは、ファイルにログ出力することが多いはずです。デバッグメッセージをファイルへ書き込むためにデフォルトハンドラを設定するには、 basicConfig() 関数を使用してください。

import logging

LOG_FILENAME = 'logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,
                    level=logging.DEBUG,
                    )

logging.debug('This message should go to the log file')

f = open(LOG_FILENAME, 'rt')
try:
    body = f.read()
finally:
    f.close()

print 'FILE:'
print body

このスクリプトを実行すると、 logging_example.out にログメッセージが書き込まれます。

$ python logging_file_example.py
FILE:
DEBUG:root:This message should go to the log file

ログファイルのローテイト

スクリプトを繰り返し実行すると、ファイルにメッセージがどんどん追加されます。プログラムを実行する度に新しいファイルを作成するには、 basicConfig()filemode 引数に 'w' を渡してください。この方法でもファイルの作成を管理できますが、それよりも次の RotatingFileHandler を使用する方がもっと簡単です。

import glob
import logging
import logging.handlers

LOG_FILENAME = 'logging_rotatingfile_example.out'

# 必要なログレベルをもつロガーを設定する
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

# ロガーに対するハンドラにメッセージを追加する
handler = logging.handlers.RotatingFileHandler(LOG_FILENAME,
                                               maxBytes=20,
                                               backupCount=5,
                                               )
my_logger.addHandler(handler)

# メッセージをログ出力する
for i in range(20):
    my_logger.debug('i = %d' % i)

# 作成されたファイルを調べる
logfiles = glob.glob('%s*' % LOG_FILENAME)
for filename in logfiles:
    print filename

この実行結果は、6つのファイルにアプリケーションのログの履歴がそれぞれ出力されます。

$ python logging_rotatingfile_example.py
logging_rotatingfile_example.out
logging_rotatingfile_example.out.1
logging_rotatingfile_example.out.2
logging_rotatingfile_example.out.3
logging_rotatingfile_example.out.4
logging_rotatingfile_example.out.5

最新のファイルは常に logging_rotatingfile_example.out です。そして、このファイルがサイズ制限に達すると、接尾辞に .1 を付けてファイル名が変更されます。既存のバックアップファイルは、接尾辞を増加させてファイル名が変更され (.1 の次は .2 になる)、 .5 のファイルは削除されます。

Note

このサンプルでは、極端な例として、わざとログサイズをかなり小さくしています。実際のプログラムは maxBytes に適切な値を設定してください。

冗長性レベル

その他の logging API の便利な機能は、異なるログレベルでメッセージを生成する仕組みです。デバッグメッセージを出力するようにしたコードは、例えば、本番システムではそういったデバッグメッセージを出力しないようにそのログレベル設定を下げます。

レベル
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
UNSET 0

ロガー、ハンドラ、ログメッセージは、それぞれのログレベルを指定して呼び出します。ハンドラとロガーがあるログレベル以上のログメッセージを出力するように設定されている場合のみ、そのメッセージを出力します。例えば、あるメッセージが CRITICAL で、そのロガーが ERROR に設定されているなら、そのメッセージは出力されます (50> 40) 。あるメッセージが WARNING で、そのロガーが ERROR に設定されているなら、そのメッセージは出力されません (30 < 40) 。

import logging
import sys

LEVELS = { 'debug':logging.DEBUG,
            'info':logging.INFO,
            'warning':logging.WARNING,
            'error':logging.ERROR,
            'critical':logging.CRITICAL,
            }

if len(sys.argv) > 1:
    level_name = sys.argv[1]
    level = LEVELS.get(level_name, logging.NOTSET)
    logging.basicConfig(level=level)

logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical error message')

このスクリプトを ‘debug’ または ‘warning’ といった引数で実行してみてください。異なるログレベルでメッセージが表示されることを確認できます。

$ python logging_level_example.py debug
DEBUG:root:This is a debug message
INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message

$ python logging_level_example.py info
INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical error message

ライブラリのログ出力

アプリケーションよりも、むしろライブラリの開発者が logging を使用すべきです。ライブラリの開発者にとっても、その作業は少ない労力で行えます。それぞれのコンテキストに、適切な名前を付けて単純にロガーを作成してください。それから、標準レベルでメッセージをログ出力します。ライブラリが一貫性のある命名規則とログレベルを選択した logging API を使用するなら、そのライブラリを利用するアプリケーションは、必要に応じてライブラリからのメッセージを表示したり、隠したりするように設定できます。

ロガーインスタンスに名前を付ける

これまでに紹介した全てのログメッセージは、そのロガーの ‘root’ に組み込まれていました。 logging モジュールは、異なる名前で階層構造をもつロガーをサポートします。特別なログメッセージをどこに出力するかを伝える簡単な方法は、それぞれのモジュールのために別々のロガーオブジェクトを使用することです。新たに作成された全てのロガーは、その親から設定を継承します。そして、ロガーへ送られるログメセージには、そのロガーの名前も含みます。それぞれのロガーは、必要に応じて別々のモジュールからのメッセージを違った方法で扱うために個別に設定できます。別々のモジュールからのログ出力する次のサンプルは、メッセージソースを追跡するのが簡単です。

import logging

logging.basicConfig(level=logging.WARNING)

logger1 = logging.getLogger('package1.module1')
logger2 = logging.getLogger('package2.module2')

logger1.warning('This message comes from one module')
logger2.warning('And this message comes from another module')

このプログラムの出力結果です。

$ python logging_modules_example.py
WARNING:package1.module1:This message comes from one module
WARNING:package2.module2:And this message comes from another module

さらに logging の設定には、オプションでメッセージのフォーマットを変更する、複数の出力先へメッセージを送る、長期間、実行されるアプリケーションの設定変更のためにソケットのインタフェースを使用するといった、もっともっとたくさんのオプションがあります。これらの全てのオプションは、標準ライブラリのドキュメントで詳しく説明されています。

See also

logging
本モジュールの標準ライブラリドキュメント
Bookmark and Share