nikkie-ftnextの日記

イベントレポートや読書メモを発信

Pythonのloggingモジュールのチュートリアルの中のフローチャートを、理解を深めるために写経する

はじめに

ういっす✌️ nikkieです。

Pythonのloggingモジュールのドキュメントには「上級ロギングチュートリアル」というものがあります。
その中の「Logging Flow」というフローチャートについて、現時点の理解をまとめます。

目次

Logging Flow写経に至るまで

先日、ロガーのフィルタと、ロガーのハンドラのフィルタでハマった経験をしました。

そこでの学びは「ロガーのフィルタとハンドラのフィルタとで、伝播されたログに対する挙動が違う」です。
このことを理解する中で、上級ロギングチュートリアルの「Logging Flow」も参照しています。

Pythonのloggingモジュールは、ここまでの体験から難しいと感じます。
ただ理解は深めていきたく、そのために「Logging Flow」を理解するのがよさそうに思われました。

そして、(これまでの経験から、特にコードに関して)自分の手を動かすことで理解はぐっと深められます。
なので、「Logging Flow」を(コードじゃなくてフローチャートですが)写経することにしました!

Mermaidを使ってフローチャートを写経していきます1

Logging Flow (powered by Mermaid)

ばーん! これが写経したLogging Flow!

ソース:https://gist.github.com/ftnext/2f7dcd1016badce3e02fb499ac7fbf92

Logging Flowによると、ログ出力されるのはこんな場合!

ユーザがロギングを呼び出した(logger.info("..."))とき、以下の場合にログ出力されます(箇条書きは「かつ」です)

  • ロガーが呼び出しのレベルで有効
  • ロガーに取り付けられたフィルタがLogRecordを却下しない
  • ロガーのハンドラが1つ以上ある(⭐️)
    • 渡ったLogRecordについて、ハンドラのレベルも有効
    • ハンドラに取り付けられたフィルタがLogRecordを却下しない

伝播(propagate)

伝播(propagate)に関しては以下のとおりです(箇条書きは「かつ」)。

  • ロガーのpropagate属性がTrue
  • 親のロガーがある

このとき、「現在のロガー」(という文字列が参照するもの)を親のロガーに置き換え2、(⭐️)から下に合流します。
合流するのが(⭐️)なので、"現在のロガー"のレベルやフィルタについてはノーチェックです。

親のロガーがあるだけ再帰的に伝播します。
最も親のロガーはルートロガーです

logging.infoの場合

logging.infoは中でlogging.basicConfigを呼び出し、ルートロガーを設定しています。

なので、ルートロガーについて「Logging Flow」をたどることになります。

  • ルートロガーが呼び出しのレベルで有効
  • ルートロガーに取り付けられたフィルタがLogRecordを却下しない
  • ルートロガーのハンドラが1つ以上ある3
    • 渡ったLogRecordについて、ハンドラのレベルも有効
    • ハンドラに取り付けられたフィルタがLogRecordを却下しない

ルートロガーは階層構造の中で一番上ですので、伝播はしません。

読み解きLogging Flow

「Logging Flow」は2つのフローからなります。

  • logger flow
  • handler flow

それぞれ見ていきましょう

logger flow

ロガーとは、上級チュートリアルによると、以下3つの仕事をするものです。
https://docs.python.org/ja/3/howto/logging.html#loggers

一つ目は、アプリケーションが実行中にメッセージを記録できるように、いくつかのメソッドをアプリケーションから呼べるようにしています。
二つ目に、ロガーオブジェクトはどのメッセージに対して作用するかを、深刻度 (デフォルトのフィルタ機構) またはフィルタオブジェクトに基づいて決定します。
三つ目に、ロガーオブジェクトは関心を持っているすべてのログハンドラに関連するログメッセージを回送します。

これを表すフローが以下です。

ソース:https://gist.github.com/ftnext/9944017bd5c827b512a675b3ee0388f0

  • 「ユーザのコードでロギング呼び出し」は、ロガーの1つ目の仕事
  • 以下がロガーの2つ目の仕事に対応しますね
    • 「ロガーは呼び出しのレベルで有効か」
    • 「ロガーに取り付けられたフィルタはレコードを却下するか」
  • 「現在のロガーのハンドラへ(LogRecordを)渡す」が、3つ目の仕事の回送ですね

伝播についてはすでに見た通りです。

「現在のロガーのハンドラに渡す」以降がhandler flowです。

handler flow

ハンドラとは、上級チュートリアルによると、
https://docs.python.org/ja/3/howto/logging.html#handlers

Handler オブジェクトは適切なログメッセージを (ログメッセージの深刻度に基づいて) ハンドラの指定された出力先に振り分けることに責任を持ちます。

これを表すフローがこちら

ソース:https://gist.github.com/ftnext/6d9542623faa9f069f22610b90178ee7

  • 「ハンドラはLogRecordのレベルで有効か」=「ログメッセージの深刻度に基づいて
  • 「ハンドラに取り付けられたフィルタはレコードを却下するか」(ハンドラのフィルタの話ですね)

終わりに

Logging Flowのフローチャート、写経して完全に理解した!

小さい文字が多くて読み解くのにはエネルギーが必要でしたが、私のloggingモジュールの理解の過程としては、今回の取り組みでハーケンが打ち込めた(足場ができた)と思います。
loggingモジュールについて、分からなくなったら今後はこの図に立ち戻ります。

そして、ありがとう、Mermaid❤️
写経する中でフローチャートのドキュメントを参照しました。

P.S. logging素振り録


  1. 先日のエントリは伏線だったのですよ✌️
  2. プログラミングでいう再代入として理解しています
  3. logging.basicConfigにより、StreamHandlerが設定されています