pythonでLoggingを使ってみる

実行環境

  • OS : Windows10
  • Python : v3.9.6

Loggingについて

Pythonを入れると標準で入ってくるモジュールです。
logging --- Python 用ロギング機能 — Python 3.9.4 ドキュメント

import logging

セットアップ

loggingインスタンスの生成

直接インスタンス化するのではなく、getLogger(name)を介してインスタンス化する事が推奨されています。

logger = logging.getLogger("hogehoge")
logger = logging.getLogger(__name__)

インスタンスの親子

インスタンスから子を作成。

# 親インスタンス
parentLogger = logging.getLogger(__name__)
# 子インスタンス
childLogger = logging.getLogger(__name__).getChild("hogehoge")

ログレベルの設定

ログを出力する閾値を設定する。
閾値を設定することで、それ以上深刻なログのみ出力される。
ロガーインスタンス初期値 : NOTSET
ルートロガー初期値 : WARNING

レベル 数値
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0
# レベル定数
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

# Debugレベルに設定
logger.setLevel(logging.DEBUG)
logger.setLevel(10)

# ルートロガー初期値確認
logger = logging.getLogger()
logger.getEffectiveLevel()  # ->  30

ログ出力

レベルごとにメソッドを使い分けて出力する。

# 各レベルで出力
logger.debug("debug")
logger.info("info")
logger.warnig("warning")
logger.error("error")
logger.critical("critical")

# 変数を出力文字内に入れる
name = "hogehoge"
logger.debug("Name:%s", name)  # ->  Name:hogehoge 

NOTSETについて

初期値のNOTSETレベルは、

ロガーがルートロガーであれば処理される、そうでなくてロガーが非ルートロガーの場合には親ロガーに委譲させる という設定で、NOTSET以外の設定を見つけるまで祖先をたどる。
ルートロガーの初期はWARNINGで設定されているため、レベル設定を行わない場合、WARNING以上しか出力されない。 引用元: Logging HOWTO — Python 3.9.4 ドキュメント

# warning以上しか出力されない
logger = logging.getLogger(__name__)
logger.info("info")  -> 
logger.warning("warning")  # -> warning

# ルートロガーのレベル設定
logging.basicConfig(level=logging.DEBUG)

basicConfigでは、ほかにフォーマットや、ハンドラなどで基本的なロギングの設定を行える

Handler

ログの送り先をハンドラとして設定する

StreamHandler

標準出力(stdout)、標準エラー出力(stderror)へ送信する

# ロガーインスタンス作成
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Handler作成
sh = logging.StreamHandler()
sh.setLevel(logging.INFO)
# loggerにHandler追加
logger.addHandler(ch)

logger.info("hogehoge") # -> hogehoge

FileHandler

ログ出力をファイルに送信する

# ロガーインスタンス作成
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# # Handler作成 出力ファイル名_LOGFILE.log
fh = logging.FileHandler("./LOGFILE.log")
fh.setLevel(logging.INFO)
logger.addHandler(fh)

logger.info("hogehoge")

# ==LOGFILE.log==
hogehoge

Formatter

表示するメッセージの書式を設定する
フォーマット文字列内に特別な文字列を配置することで、日付やログレベルなどをメッセージに含められる。 フォーマッタの初期値は%(message)sのみで、メッセージだけが出力される

出力される内容
%(asctime)s 日時
%(name)s ロガーインスタンス
%(levelname)s ログレベル
%(message)s メッセージ
# ロガーインスタンス作成
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Handler作成
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# Formatter作成・追加
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
# loggerにHandler追加
logger.addHandler(ch)

logger.info("hogehoge") # -> 2021-07-18 00:00:00,000 - __main__ - INFO - hogehoge
logger.warning("hogehoge") # -> 2021-07-18 00:00:00,000 - __main__ - WARNING - hogehoge
logger.error("hogehoge") # -> 2021-07-18 00:00:00,000 - __main__ - ERROR - hogehoge
logger.critical("hogehoge") # -> 2021-07-18 00:00:00,000 - __main__ - CRITICAL - hogehoge

設定ファイルよりセットアップ

いままでの設定はコード内で行っていたが、
設定ファイル(.conf)を事前に定義して読み込みを行う事もできる。

# ==logging.conf==

# logger keys "root" 
[loggers]
keys=root 
# handler keys "streamHandler","fileHandler" 
[handlers]
keys=streamHandler,fileHandler
# formatter keys "formatter"
[formatters]
keys=formatter
# "root" logger setup
[logger_root]
level=DEBUG
handlers=streamHandler,fileHandler
# "streamHandler" handler setup
[handler_streamHandler]
class=StreamHandler
level=DEBUG
formatter=formatter
# "fileHandler" handler setup
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=formatter
args=('LOGFILE.log', 'w')
# "formatter" formatter setup
[formatter_formatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
# conf読み込み
logging.config.fileConfig("./logging.conf")
# loggerインスタンス生成
logger = logging.getLogger(__name__)

辞書型で定義してセットアップ

コード内で辞書型で定義することもできる。
設定内容は設定ファイルでの設定と同じ。

# 辞書型で設定内容を作成
logging_conf = {
    'version': 1,
    'formatters': {
        'formatter': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        },
    },
    'handlers': {
        'streamHandler': {
            'level':'DEBUG',
            'class':'logging.StreamHandler',
            'formatter': 'formatter'
        },
        'fileHandler':{
            'level':'DEBUG',
            'class':'logging.FileHandler',
            'formatter': 'formatter',
            'filename': 'LOGFILE.log',
            'mode': 'w'
        },
    },
    'loggers': {
        'root': {
            'handlers': ['streamHandler', 'fileHandler'],
            'level': 'DEBUG',
        }
    }
}

# 辞書型で読み込み
logging.config.dictConfig(logging_conf)
# インスタンス作成
logger = logging.getLogger(__name__)