📖

python logging 指針

2022/06/18に公開

loggingの良い感じの使い方がイマイチわからなかったので、ネットの記事を漁って自分用の指針を作りました。
自分用ではありますが、loggingのプラクティスがわからん方の参考になれば幸いです。
ただ、この指針はバージョン1であり、完成度が高くないです。その点はご容赦いただると...。
(間違ってるところは指摘していただけると大変嬉しい)

指針

  1. 名前付きロガーでログ生成を行うこと。ルートロガーで生成しない。
  2. 不都合がない限りは、ファイル単位でロガーを用意すればいい。
  3. 原則、ハンドラーはルートロガーだけに追加する。
  4. 例外として、特定のロガー配下のログを別出力したい場合は、そのロガーにハンドラーを追加する
  5. 原則、「伝播なし(propagate=False)」は避けた方が良い。が、「4.」の場合や外部ライブラリのログがうるさい場合は設定してもよい。
  6. ログ出力のフォーマットは「%(asctime)s - %(levelname)s:%(name)s:%(message)s」にしておくと良い。
  7. ルートロガーを含めた全ロガーの細かい設定は、logging.iniファイルを使って行う。
  8. 原則、ルートロガー以外のロガーはデフォルト設定で良い。つまり、logging.iniファイルには、ルートロガー以外の設定を記載しなくてもいい。後に必要になったら、都度設定を追加していく。

指針の意図

1. について

ルートロガーで生成してはいけない。ロガー階層構造のメリットを得られなくなる。
logging.infoは、ルートロガーでログを生成してしまうので使わない方がいい。

NG
import logging

logging.info('hogehoge')
OK
import logging

logger = logging.getLogger(__name__)
logger.info('hogehoge')

2. について

複雑な状態を生まないよう出来るだけシンプルに努める。
とは言うものの、正直この指針は自信ない。
が、変に独自の名前付きルールを管理するよりシンプルで良さげだと見ている。

3. について

以下二つの性質を考えると、無闇やたらにハンドラーを追加しようとは思わないはず

  1. ログ出力はロガーに追加されてるハンドラーが行う
  2. ログは親に伝播し続けてルートロガーまで回る(propagateがTrueである限り)

つまり、あちこちのロガーにハンドラーを追加すると、同じようなログが大量に発生してしまう。
全てのログが最終的にルートロガーまで回るのだから、ルートに出力を任せちゃうのがシンプル。

4.について

とはいえ「このログは別の出力方法を採用したい(ex:別ファイルに記録したい)」と言う要求もある。
そういう限定的な出力を行いたいなら、個別のログにハンドラーを追加するほかない。

5. について

例えば「4.」の指針に従ったからと言って、ログの伝播が止まるわけではない。
ログは明示的に止められない限り伝播し続ける。
伝播を止めるためには、伝播を止めたいロガーにpropagate=Falseの設定を行う必要がある。

6. について

結構一般的なフォーマットの形。
大体の記事やStackoverflowで、この4つの情報が載せられてる。
%(name)s%(filename)sにしてるところもあるが、個人的には%(name)sの方が好み。
この4つの情報があれば、いつどこでどのレベルのログが流れたのかをすぐ把握できる。

7. について

複数のロガーがある場合に有効。
ロガーのログレベルや、ハンドラーを設定する際、いちいち対象ロガーを探す必要がなくなる。
また、各ロガーの設定が一目見てわかるのも最高なポイント。

8. について

最初は特に、各ロガーの設定を気にしなくても良い。
ルートロガーの設定だけ気にしておけばOK。
「ロガーのログレベルをちゃんと考える必要があるんじゃ...」となるかもだが、必要になったタイミングで考えれば良い。

loggingの前提知識

  • Loggerインスタンスがログ生成を行う
  • Loggerインスタンスは親子構造になっており、ルートロガーを最上位の親にして下に名前付きロガーが連なっている
  • あるLoggerインスタンスが生成したログは、親を辿ってルートロガーまで伝播する
  • ログの出力(ex: 標準出社、ファイル出力)自体は、HandlerインスタンスがLoggerインスタンスに追加されてないとできない
  • ログ出力のフォーマットはカスタム可能で、FormaterインスタンスをHandlerインスタンスに設定する必要がある
  • あるLoggerインスタンスからの伝播を止めたい場合は、そのインスタンスのpropagateをFalseにすると良い
  • Loggerインスタンスはシングルトンである。覚えておくと驚かずに済む。

参考記事

loggingの基本を図解で分かりやすく教えてくる

ルートロガーにだけハンドラーを追加すれば良いのだと教えてくれた

設定ファイルのことを教えてくれた

Discussion