標準モジュールのloggingについて紹介(上級編)

f:id:monozukuri-bu:20190218213229p:plain
jupyter_notebook

モノづくり部のokadaです。

前回はloggingの基本編を書きました。
今回は上級編を書きたいと思います。
内容としては上級ロギングチュートリアルの一部紹介です。

Python環境

以下の環境で動作確認しています。

Ubuntu 18.04
Python 3.6.5

loggerによるログ出力

まずは用語を簡単に説明します。

・ロガー(logger):ログ出力のためのオブジェクト
・フォーマッタ(formatter):ログ出力形式
・ハンドラー(handler):出力先

次にプログラムの流れを説明します。

  1. ロガー生成
  2. フォーマッタ生成
  3. ハンドラー生成
  4. ハンドラーにフォーマッタを設定
  5. ロガーにハンドラーを設定

ロガーの生成にはlogging.getLoggerメソッドを使用します。
一般的に__name__を引数に指定します。

フォーマッタの生成にはlogging.Formatterメソッドを使用します。
引数には基本編で説明したフォーマットを指定します。

ハンドラーの生成ではloggingdで準備されたhandlersを使用します。
ここではStreamHandlerとFileHandlerを使用します。
StreamHandlerはコンソールに出力します。
FileHandlerは引数で指定したファイルに出力します。
尚、ハンドラーは複数指定可能でそれぞれにログレベルを設定出来ます。

上記以外のハンドラーについては公式ドキュメントを参照ください。
https://docs.python.jp/3/library/logging.handlers.html

では、下記コードをlog.pyという名前で保存します。

import logging

# ロガー生成
logger = logging.getLogger(__name__)
# ログレベルを設定(loggerのログレベル以上のハンドラーしか出力されません)
logger.setLevel(logging.DEBUG)

# フォーマッタ生成
formatter = logging.Formatter("[%(asctime)s %(levelname)s] %(message)s")

# ハンドラー生成
log_stream_handler = logging.StreamHandler()
# StreamHandlerにフォーマッタを設定
log_stream_handler.setFormatter(formatter)
# StreamHandlerのログレベルを設定
log_stream_handler.setLevel(logging.INFO)

# ロガーにハンドラーを設定
logger.addHandler(log_stream_handler)

# ログ出力
logger.critical("critical")
logger.error("error")
logger.warning("warning")
logger.info("info")
logger.debug("debug")

下記のコマンドで実行します。

> python log.py

[2019-02-18 00:31:35,161 CRITICAL] critical
[2019-02-18 00:31:35,161 ERROR] error
[2019-02-18 00:31:35,161 WARNING] warning
[2019-02-18 00:31:35,161 INFO] info

コンソールにINFO以上のレベルのログメッセージが出力されましたね。
次にFileHandlerを追加してみます。
ログレベルはERRORです。

import logging

# ロガー生成
logger = logging.getLogger(__name__)
# ログレベルを設定(loggerのログレベル以上のハンドラーしか出力されません)
logger.setLevel(logging.DEBUG)

# フォーマッタ生成
formatter = logging.Formatter("[%(asctime)s %(levelname)s] %(message)s")

# ハンドラー生成
log_stream_handler = logging.StreamHandler()
# StreamHandlerにフォーマッタを設定
log_stream_handler.setFormatter(formatter)
# StreamHandlerのログレベルを設定
log_stream_handler.setLevel(logging.INFO)

# ハンドラー生成
log_file_handler = logging.FileHandler("test.log")
# FileHandlerにフォーマッタを設定
log_file_handler.setFormatter(formatter)
# FileHandlerのログレベルを設定
log_file_handler.setLevel(logging.ERROR)

# ロガーにハンドラーを設定
logger.addHandler(log_stream_handler)
logger.addHandler(log_file_handler)

# ログ出力を行う
logger.critical("critical")
logger.error("error")
logger.warning("warning")
logger.info("info")
logger.debug("debug")

実行します。

> python log.py

[2019-02-18 00:36:44,402 CRITICAL] critical
[2019-02-18 00:36:44,402 ERROR] error
[2019-02-18 00:36:44,402 WARNING] warning
[2019-02-18 00:36:44,402 INFO] info

コンソールにINFO以上のレベルのログメッセージが出力され、log.pyにtest.logのファイルが作成されました。
test.logにはERROR以上のレベルのログメッセージが出力されています。

loggingの環境設定

loggingの環境設定は以下3種類で設定出来ます。

  1. 上記のようにPythonコードで明示的にロガー、フォーマッタ、ハンドラーを生成
  2. 設定ファイルを作成し、fileConfigメソッドで読み込み
  3. 設定辞書を作成し、dictConfigメソッドで読み込み

ここでは2のfileConfigを見てみたいと思います。

下記コードをlogging.confという名前で保存しましょう。

[loggers]
keys=root

[handlers]
keys=logStreamHandler, logFileHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=logStreamHandler, logFileHandler

[handler_logStreamHandler]
class=StreamHandler
level=INFO
formatter=simpleFormatter
args=(sys.stdout,)

[handler_logFileHandler]
class=FileHandler
level=ERROR
formatter=simpleFormatter
args=('test.log',)

[formatter_simpleFormatter]
format=[%(asctime)s %(levelname)s] %(message)s

各セクションについて簡単にまとめます。

セクション 説明
loggers 使用するロガーの名前をカンマ区切りで設定
handlers 使用するハンドラーの名前をカンマ区切りで設定
formatters 使用するフォーマッタの名前をカンマ区切りで設定
logger_ロガー名 使用するロガーの設定
handler_ハンドラー名 使用するハンドラーの設定
formatter_フォーマッタ名 使用するフォーマッタの設定

詳細については公式ドキュメントを参照ください。
https://docs.python.jp/3/library/logging.config.html#configuration-file-format

次にlog.pyを下記コードに修正して実行してみましょう。
fileConfigの引数には作成したlogging.confを設定します。

import logging.config

logging.config.fileConfig('logging.conf')

logger = logging.getLogger(__name__)

logger.critical("critical")
logger.error("error")
logger.warning("warning")
logger.info("info")
logger.debug("debug")

実行します。

> python log.py

[2019-02-18 11:05:33,087 CRITICAL] critical
[2019-02-18 11:05:33,087 ERROR] error
[2019-02-18 11:05:33,087 WARNING] warning
[2019-02-18 11:05:33,087 INFO] info

コンソールにINFO以上のレベルのログメッセージが出力され、log.pyにtest.logのファイルが作成されました。
test.logにはERROR以上のレベルのログメッセージが出力されています。
設定ファイルにまとめているのでPythonコードがスッキリして見やすいですね。

本記事では紹介しませんでしたが、dictConfigを使用すると辞書形式の設定情報を読み込みます。
Pythonコードで辞書に設定情報を記載して読み込ませたり、jsonファイルで設定情報を持たせておき読み込ませたり、yamlファイルで設定情報を持たせておき読み込ませたり出来ます。
詳細は公式ドキュメントを参照ください。
https://docs.python.jp/3/library/logging.config.html#logging.config.dictConfig

もっとloggingについて勉強したいという方は、公式ドキュメントのLogging クックブックを見たり、OSSのlogging部分を見たり等して色々な使い方を学んで頂ければと思います。

以上、loggingの上級編でした。