Pythonでloggingモジュール使ってライブラリ内でログ出力する時のまとめ
はじめに
Pythonでloggingモジュールを使う際の備忘録です。
下記の要求を実現することを目的としています。
- ライブラリ化したいコードがあり、デバッグ目的などでログを出力させたい。
- ライブラリで発生した例外のトレースも同じログに出力させたい。
- ライブラリを利用するスクリプトがあり、ログの出力先やログレベルなどをカスタマイズしたい。
方法
ライブラリ側のロギング設定
logging.getLogger()でモジュール名(__name__)を指定して名前付きでロガーを作成します。
ロガーは階層構造になっており、ここで作成したロガーはルートロガーの子ロガーとなります。
ルートロガーはlogging.getLoggerで名前を指定しない場合に取得できますが、 ライブラリ自身はルートロガーは使用せずに、モジュール毎に名前付きで作成されたロガーでログ出力するのが良いようです。
ライブラリ側で作成したロガーにはNullHandlerという何もしない(ログ出力しない)ハンドラーを設定します。
NullHandlerを設定されたロガーは、イベントが記録(ログ出力)されても何もしませんが、 ロガーのpropagate変数がTrueの場合には、イベントが上位ロガーに伝播されるため、そこで設定されたハンドラーによりイベントが処理されます。
ライブラリ利用側ではこの仕組みを利用し、ここで作成したロガーかより上位ロガーに対してロギング設定していきます。
from logging import getLogger, DEBUG, NullHandler logger = getLogger(__name__) logger.addHandler(NullHandler()) logger.setLevel(DEBUG) # ロガーで記録されたイベント(ログ出力)が上位ロガーに伝播されるかどうか。 # True(デフォルト値)の場合、親ロガーを通じルートロガーまで伝播し、上位ロガーのハンドラー設定に応じてログ出力される。 # ロガーとその上位ロガーそれぞれでハンドラーが設定されていた場合は重複してログ出力される。 logger.propagate = True # ロガーを使用してログ出力する(NullHandlerのためこのままでは何も出力されない) logger.debug("Hello World") # 例外のトレースをロガーに出力する(NullHandlerのためこのままでは何も出力されない) try: # ここで例外を発生させる except Exception as e: logger.warning(e, exc_info=True)
ライブラリ利用側のロギング設定
例として、ファイルにログ出力して日時でローテーションするロギング設定を記述します。
先にライブラリ側のロギング設定でも説明しましたが、ライブラリ内で作成したロガーに対して記録されたイベントは上位ロガーを通じてルートロガーにまで伝播されます。
ここでは、簡単のためにlogging.getLogger()で名前を指定せずルートロガーを取得してロギング設定しています。
具体的なロギング設定については参考文献を参照してください。
from logging.handlers import TimedRotatingFileHandler import logging # ルートロガーを取得 logger = logging.getLogger() # フォーマッターを作成 formatter = logging.Formatter('%(asctime)s %(name)s %(funcName)s [%(levelname)s]: %(message)s') # ハンドラーを作成しフォーマッターを設定 handler = TimedRotatingFileHandler( filename="path/to/log.log", when="D", interval=1, backupCount=31, ) handler.setFormatter(formatter) # ロガーにハンドラーを設定、イベント捕捉のためのレベルを設定 logger.addHandler(handler) logger.setLevel(logging.DEBUG)
まとめ
- ライブラリ側では、何もしないロガーを作成してイベントを記録する。
- ライブラリ利用側では、ルートロガーを取得してロギング設定する。
- ライブラリ側およびライブラリ利用側に関らず、ルートロガーにイベントを記録するのは避ける。
参考
ライブラリ側とその利用側のloggingの使い分け方
Logging HOWTO — Python 3.6.3 ドキュメント
ログ出力のための print と import logging はやめてほしい - Qiita
Python標準のloggingでログをJSON形式で出力する - Qiita
例外処理時にエラートレースを出力する方法
29.9. traceback — スタックトレースの表示または取得 — Python 3.6.3 ドキュメント
loggingモジュールで例外処理時にトレース出力する方法
loggingで例外情報を出力する | Python Snippets