背景
- logging.loggerを拡張していく中でLoggerオブジェクトをフィールドに持つようなLoggerWrapperオブジェクトを作りたくなることがあると思われる。
- ただしその場合、LogRecordオブジェクトに含まれる呼び出し元の情報=スタック情報(
pathname
,lineno
,func
)が、LoggerWrapperのlogメソッドを参照してしまい、元々の呼び出し元の情報が出力されなくなってしまう。 - そのため、以下の方法でスタック情報を正しく出力する必要がある。
- 以下の方法は、参照するスタックの深さを変更するものである。
スタック情報の出力方法
Python 3.8以降: loggingのstacklevelを利用
Python3.8からloggingモジュールで今回のユースケースに対するサポートが入った。
利用方法としては以下の二種類が考えられる。
ログ出力のキーワード引数として渡す
logger.info(msg, stacklevel=2)
stacklevel
というのが追加されたパラメータである。参照したい呼び出し元までの深さを設定する。
loggerオブジェクトのメソッドを使って参照する
stack_filename, stack_lineno, stack_function = logger.findCaller(True, 3)[0:3]
- findCallerの第2引数に深さを渡す。
- LoggerAdapterやLoggerFormatterの中でスタック情報をまとめたい場合はこちらを使うのが良さそう。
Python 3.7以前: 独自関数を定義
loggingパッケージでのサポートはないので、 inspect
パッケージを利用して、スタック情報を取得する関数を定義する。
[2]が深さを表す
import inspect
def stack_info() -> dict:
stack = inspect.stack()[2]
return {
'stack_filename': stack.filename,
'stack_lineno': stack.lineno,
'stack_function': stack.function,
}
利用例
logger.info(msg, extra=stack_info())
終わり
- LoggerWrapperオブジェクトを利用する場合、今回のようにスタック情報を正しく出力するために仕込みが必要になる。
- そのため、logging.LoggerAdapterなどを利用してやり切れないか検討した上でLoggerWrapperオブジェクトの導入を検討した方が良さそう。