Python でのロギングにオリジナルのフォーマッタを使う方法をご紹介します。
Python に同梱の標準ライブラリ logging
についてのお話です。
やるべきことはシンプルで、 logging.Formatter
を継承したクラスを作成してそれをフォーマッタとしてセットするだけです。
Python の公式ドキュメントを読めばそのやり方が書かれてはいるのですが、経験の無い人には少しわかりづらいのではないかと思いますので、かんたんな例を使って説明します。
次のサンプルは、ログの名前を大文字に変換して出力するだけのシンプルなフォーマッタ CustomFormatter
を定義して使用する例です。
custom_formatter.py
:
import logging
class CustomFormatter(logging.Formatter):
def format(self, record):
record.name = record.name.upper()
return super().format(record)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {},
'formatters': {
'custom_formatter': {
'()': CustomFormatter,
'format': '%(asctime)s\t%(name)s\t%(message)s',
},
},
'handlers': {
'sample': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': '/tmp/python.log',
'formatter': 'custom_formatter',
},
},
'loggers': {
'special': {
'level': 'INFO',
'handlers': ['sample'],
'propagate': True,
},
},
}
logging.config.dictConfig(LOGGING)
logger = logging.getLogger('special')
logger.info('Hello')
このファイルを実行すると、ファイル /tmp/python.log
に次のようなログが出力されます。
2020-09-09 18:33:26,144 SPECIAL Hello
ログの名前にあたる special
が大文字 SPECIAL
になって出力され、望んだとおりに CustomFormatter
が使えていることが確認できます。
オリジナルのフォーマッターを定義するときは、上のように logging.Formatter
を継承しメソッド format()
を持つクラスを作成します。
class CustomFormatter(logging.Formatter):
def format(self, record):
...
この format()
の引数 record
は 1 件のログレコードを表す logging.LogRecord
クラスのオブジェクトで、以下のようなアトリビュートを持っています( Python 3.8 で確認しています。バージョンが異なると変わる可能性があります)。
args
created
exc_info
filename
funcName
levelname
levelno
lineno
module
msecs
msg
name
pathname
process
processName
relativeCreated
stack_info
thread
threadName
どんな値が入っているのかはそれぞれの名前からある程度推測できますが、厳密に知りたい場合は公式ドキュメントの logging
のページの以下の箇所または logging/__init__.py
ファイルを確認するとよいと思います。
- LogRecord attributes | Logging facility for Python — Python documentation
cpython/__init__.py
at main · python/cpython · GitHub
LogRecord
オブジェクトにはテンプレート文字列 msg
に args
を挿入した文字列を返すメソッド getMessage()
もあります。
メソッド format()
が戻り値として返すべき値は 1 件のログレコードを表す文字列です。
ログハンドラがログレコードを出力するときにこの format()
が呼ばれます。
logging.Formatter
はメソッド format()
を持っているので、ちょっとしたカスタマイズであれば super().format(record)
でそれを利用できます。
カスタマイズの程度が大きくなると logging.Formatter
が提供する format()
は使えないので、 record.getMessage()
等を使ってフォーマット済み文字列を独自に生成する必要があります。
幅広い用途に使える汎用のフォーマッタを作りたければ、公式のドキュメントに加えて logging
のコードをチェックする必要があります。
たいていのケースは format()
を定義するだけで対応できますが、 format()
だけでは対応しきれない場合は次のように __init__()
メソッドを上書きする必要があります:
import csv
import logging
class CsvFormatter(logging.Formatter):
"""CSV 形式で出力するフォーマッター"""
def __init__(self, fmt=None, datefmt=None, style='%', validate=True):
# レコードごとに csv writer と StrnigIO を生成しなくて済むように最初に用意する
self.output = io.StringIO()
self.writer = csv.writer(self.output, delimiter='\t')
def format(self, record):
...
ということで、かんたんにですが Python でオリジナルのロギングフォーマッタを使う方法についてでした。
参考: