とほほのPython入門 - ロギング

トップ > Python入門 > ロギング

目次

ログレベル

ログレベルには下記の5つがあります。通常は WARNING 以上のログのみが出力されます。

DEBUG		# デバッグログ
INFO		# 情報ログ
WARNING		# 警告ログ
ERROR		# エラーログ
CRITICAL	# 致命的エラーログ

基本的なロギング

ロギングによる出力

下記の様にしてログを出力します。

import logging

logging.debug("This is DEBUG message.")
logging.info("This is INFO message.")
logging.warning("This is WARNING message.")
logging.error("This is ERROR message.")
logging.critical("This is CRITICAL message.")

下記の様にフォーマットを指定することもできます。

logging.error("Can't open file: %s", filename)

ログレベルをメソッド名ではなく第一引数で指定することもできます。

logging.log(logging.ERROR, "...")

文字列からログレベルを得るには getattr() を使用します。

level = getattr(logging, "ERROR")
logging.log(level, "...")
ロギングのカスタマイズ

basicConfig() を用いてコンフィグの出力先ファイル名、レベル、フォーマット等を変更することができます。

logging.basicConfig(
    filename="example.log",
    level=logging.DEBUG,
    format="[%(levelname)s] %(message)s",
    datefmt="%m/%d/%Y %I:%M:%S %p"
)

下記のパラメータを指定できます。

filename	# 出力先ファイル名
filemode	# ファイル出力モード。(デフォルト:filemode='a')
stream		# 出力先ストリーム。(デフォルト:stream=sys.stderr)
format		# 出力フォーマット。(詳細)(デフォルト:format='%(levelname)s:%(name)s:%(message)s')
datefmt		# 日付フォーマット
level		# 出力レベル。(デフォルト:level=logging.WARNING)
style		# フォーマットスタイル。(デフォルト: style='%')
handlers	# 出力ハンドラリスト。
force		# force=Trueを指定すると利用前に全ハンドラが一度クローズされる。
encoding	# エンコーディングルール。encoding='utf-8'など
errors		# エンコードに失敗した場合のふるまい。(詳細)

handlers は下記の様に指定します。handlers を指定した場合は filenamestream は指定できません。

handlers=[
    logging.FileHandler("debug.log"),
    logging.StreamHandler(sys.stdouot)
]

style には下記のいずれかを指定できます。

'%'	# printf-style形式
'{'	# str.format形式
'$'	# string.Template形式
例外情報のロギング

ロギングメソッドに exc_info=sys.exc_info() を指定すると、例外情報を出力します。

logging.error("...", exc_info=sys.exc_info())

または、logging.exception() を使用することもできます。

logging.exception("...")
スタック情報のロギング

ロギングメソッドに stack_info=True を指定すると、スタック情報を出力します。

logging.error("...", stack_info=True)

高度なロギング

ロガーによる出力

ロギング(logging) の代わりにロガー(logger) を用いることで、モジュール毎にログの出力先やレベルを詳細にカスタマイズすることができるようになります。logger_name にはロガー名を指定します。ロガー名には通常モジュール名 (__name__) を指定します。ロガー名によってログのふるまいをカスタマイズします。

from logger import getLogger

logger = getLogger(logger_name)
logger.debug("This is DEBUG message.")
logger.info("This is INFO message.")
logger.warning("This is WARNING message.")
logger.error("This is ERROR message.")
logger.critical("This is CRITICAL message.")
ロガーのカスタマイズ

ロガーをカスタマイズするには下記のような YAML ファイル(config.yaml)を用意します。"exampleLogger" というロガー名で生成されたロガーは、"console""file" というふたつのハンドラにログを出力します。"console" ハンドラは StreamHandler で標準出力に、"file" ハンドラは FileHandler/var/log/myapp/myapp.log にログを書き出します。フォーマットはいずれも "simple" フォーマッタで定義されたものを使用します。"exampleLogger 以外の名前で作成されたロガーは "root" の定義に従います。

version: 1
formatters:
  simple:
    format: '%(asctime)s:%(name)s:%(levelname)s:%(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
  file:
    class: logging.FileHandler
    level: INFO
    filename: '/var/log/myapp/myapp.log'
    formatter: simple
loggers:
  exampleLogger:
    level: DEBUG
    handlers: [console, file]
    propagate: no
root:
  level: DEBUG
  handlers: [console]

このファイルを次のようにして読み込みます。

import yaml
from logging import config, getLogger

config.dictConfig(yaml.safe_load(open("config.yaml").read()))
logger = getLogger("exampleLogger")
logger.error("This is ERROR message.")

フォーマット

ログのフォーマットには次のような要素を指定できます。

%(asctime)s		# 生成時間。YYYY-MM-DD HH:MM:SS,UUU 形式。datefmtでフォーマット変更可能
%(created)f		# 生成時間。time.time()が返却する形式
%(msecs)d		# 生成時間のミリ秒部
%(relativeCreated)d	# logginモジュールが読み込まれてからの経過時間(ミリ秒)
%(levelname)s		# レベル名(DEBUG, INFO, WARNING, ERROR, CRITICAL)
%(levelno)s		# レベル番号。DEBUGは10, INFOは20など
%(module)s		# モジュール名
%(pathname)s		# パス名
%(filename)s		# ファイル名
%(funcName)s		# 関数名
%(lineno)d		# 行番号
%(message)s		# ログメッセージ
%(name)s		# ロガー名
%(process)d		# プロセスID
%(processName)s		# プロセス名
%(thread)d		# スレッドID
%(threadName)s		# スレッド名

ロギング関数に extra 引数を指定することで、独自要素を追加することもできます。

# format: '%(user_id)s ...'
logging.info("Login", extra={"user_id": "U123456"})

時刻に関するフォーマット (datefmt) については下記を参照してください。

ハンドラ

標準では下記のハンドラが用意されています。個々のハンドラはスレッドセーフで、複数スレッドのロギングが互いを邪魔することはありません。

StreamHandler			# ストリームハンドラ。sys.stdoutなど
FileHandler			# ファイルハンドラ
RotatingFileHandler		# ローテートファイルハンドラ
TimedRotatingFileHandler	# 時間ローテートファイルハンドラ
SocketHandler			# TCPソケットハンドラ
DatagramHandler			# UDPソケットハンドラ
SMTPHandler			# SMTPハンドラ
SysLogHandler			# Syslogハンドラ
NTEventLogHandler		# Windows NTイベントハンドラ
MemoryHandler			# メモリハンドラ
HTTPHandler			# HTTPハンドラ
WatchedFileHandler		# 監視ファイルハンドラ。ファイルが変更を監視し変更時は開きなおす
QueueHandler			# キューハンドラ。queueモジュールなど
NullHandler			# ヌルハンドラ。ログを読み捨てる

詳細は下記を参照してください。


Copyright (C) 2022 杜甫々
初版:2022年1月23日、最終更新:2022年10月9日
http://www.tohoho-web.com/python/logging.html