BUNSEN

個人的な学習ログ

logging.config.fileConfig()についてまとめる

概要

log出せ、指定の形式でだせ、ファイルに保存しろ、コンソールにも出力しろ。

そんな時に出会ったloggingモジュール、今まで設定をちまちま毎回書いていてめんどくさいなと感じていた。 たがファイルに設定を記述しておくだけで読み込んでloggerを初期化してくれる便利な機能があるらしい!そんなfileConfigについて調べたところどうも覚えることは難しそう。

だからまとめる。

Logger の構造

PythonのLoggerの構造は以下のようになっている

    root
    ├───────────────────┐
    user1               user2
    ├─────────┐         ├─────────┐
    user1_1   user1_2   user2_1   user_2_2

rootのみがデフォルトで作成されており、logging.info()logging.error()などのlogging直下のコマンドを使用すると参照される。 また、logging.getLogger()で引数なしまたはrootを引数にするとrootLoggerが返却される

rootLogger以外はすべてユーザが定義する必要がある。

e.g.)

  • user1:logging.getLogger("user1")
  • user1_1: logging.getLogger("user1.user1_1") or logging.getLogger("user1").getChild("user1_1")

ちなみにLogger間のLogメッセージの遷移は以下のようになっている。 それぞれのLoggerの設定に従い処理をした後に上位のLoggerにLogメッセージを伝搬する。

log_message > user1_1 > user1 > root
              ↓output   ↓output ↓output

Logger の設定

Loggerを設定するにはHandlerやFormatter、Filterなどを定義し、Loggerオブジェクトに投入する必要がある。

しかし、その設定は長くなりプログラムファイル上部を大きく占めてしまう。

これらの設定を別ファイルに保存し、プログラムファイル自体を簡潔にするのがlogging.config.fileConfig()である。

fileConfig()使用方法

  • 1ファイル単体でのみLoggerを使用する場合

    • main.py

      from logging import getLogger, config
      
      config.fileConfig('./config/logging.conf')
      logger = getLogger(__name__)
      
      logger.info("this is a information message.")
      
  • 複数ファイルで設定を共有する場合(特別異なることはないがimportの順番で詰まった)

    • main.py

      from logging import getLogger, config
      
      config.fileConfig('./config/logging.conf')
      logger = getLogger(__name__)
      
      import child
      
      logger.info("this message from main.py")
      
    • child.py

      from logging import getLogger
      
      logger = getLogger(__name__)
      
      logger.info("this message from child.py")
      

fileConfig() 設定ファイル書式

以下の例では、これらの設定をしている

  • rootLogger
    • logFileHandler: Debug以上をファイルに書き出し
    • consoleHandler: Info以上を標準出力に書き出し
[loggers]
keys=root

[handlers]
keys=logFileHandler,consoleHandler

[formatters]
keys=logFileFormatter,consoleFormatter

[logger_root]
level=DEBUG
handlers=logFileHandler,consoleHandler

[handler_logFileHandler]
class=FileHandler
level=DEBUG
formatter=logFileFormatter
args=("./log/app.log", "w", "utf-8")

[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=consoleFormatter
args=(sys.stdout,)

[formatter_logFileFormatter]
format=%(asctime)s|%(levelname)-8s|%(name)s|%(funcName)s|%(message)s

[formatter_consoleFormatter]
format=[%(levelname)-8s]%(funcName)s - %(message)s

[loggers]

[handlers]

[formatters]

[loger_<logger_name>]

  • level: メッセージを出力する最低レベルを指定する。Handlerに渡す前に処理されるので注意。
  • handlers: 適用するHandlerインスタンス名を指定する

[hander_<handler_name>]

  • class:実装するHandlerクラスを指定する
    • StreamHandler: メッセージを指定されたストリームに出力する。
    • FileHandler: メッセージを指定されたファイルに出力する。
  • level: 指定されたレベル以上のメッセージのみが出力される。
  • formatter: 出力時のメッセージ成型に使用するFormatter名を指定する。
  • args: Handlerクラスをインスタンス化する際に使用する引数。Handlerクラスの公式ドキュメントを参照すること。

    ※tuple形式で渡すので引数のキーワード指定は使用不可、位置指定で渡す。

    ※tuple形式で渡すので引数が1つの場合は,を忘れないこと

[formatter_<formatter_name>]

  • format: 使いそうなもののみ抜粋。詳細はこちらまで
書式 説明
%(asctime)s ログ生成日時 "yyyy-mm-dd HH:MM:SS,sss"
%(filename)s 呼び出し元ファイル名
%(funcName)s 呼び出し元関数名
%(levelname)s ログレベル ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
%(lineno)d 呼び出し元ファイル内の行番号
%(message)s 呼び出し時に引数で指定した値logger.info("ここ")
%(module)s 呼び出し元モジュール名
%(name)s 使用されたlogger名

注意事項

fileConfig()ではFilterの項目は設定できない。

使用したい場合はdictConfig()を使用しろと公式にあったので合わせて参照してほしい。