Pythonのloggingを使いこなす!詳解ロギング Ver.1.0.2

303, 2021-08-10

目次

Pythonのloggingの簡単な使い方

Pythonには標準ライブラリにログ関連の処理を行ってくれるloggingというモジュールがあります。
このloggingを使うとログの出力を簡単に行うことが出来ます。

この記事ではloggingの使い方を簡単に解説します。
結論から言うとloggingは↓のように使います。

import logging

logging.basicConfig(level=logging.DEBUG)  # ロギングレベルの設定

logging.debug('DEBUGです')  # DEBUG:root:DEBUGです

具体的には↓を見ていきます。

  • loggingのインポート方法

  • loggingの概念

  • ロガーの概念と簡易的な関数

  • ロギングレベルの概念

  • ルートロガーの設定方法(basicConfig)

  • logging.debug()の使い方

  • その他出力系の関数の使い方

  • フォーマットの指定

  • ファイルへの出力

参考記事
logging --- Python 用ロギング機能 — Python 3.9.4 ドキュメント
Logging HOWTO — Python 3.9.4 ドキュメント

loggingのインポート方法

loggingは↓のようにインポートします。

import logging

↑のようにするとloggingが持っている各種関数、クラスを使うことが出来るようになります。

loggingの概念

loggingの概念について簡単に説明します。
loggingの中核的な概念は↓の2つです。

  • ロガー

  • ロギングレベル

ロガーの概念と簡易的な関数

loggingは「ロガー」と呼ばれるオブジェクトを作成して、そのオブジェクトを使ってログを記録します。
これは単純なクラスから生成されます。
ロガーは複数持つことが可能で、この内、もっとも基本的なロガーを「ルートロガー」と言います。
ルートロガーはRootLoggerというクラスから作成されています。

ルートロガーさん、「兄貴」と呼ばせてください

ロガーはlogging.getLogger()で取得することが可能です。
しかし、ルートロガーに限ってはlogging.debug()などの簡易的な関数が用意されていて、こういった関数を通してルートロガーを使うことができます。
この記事ではこれらの簡易的な関数をメインに解説します。
logging.getLogger()でロガーを取得してログを出力する方法については解説しません。

ロギングレベルの概念

ロガーで出力する各ログは「ロギングレベル」という定数で割り振られて、ロガーに設定されたあるレベルの値以上のレベルのログだけ出力する……などという風に扱われます。
逆に言うとロガーに設定したロギングレベルより下のログは出力されません。

レベル

数値

CRITICAL

50

ERROR

40

WARNING

30

INFO

20

DEBUG

10

NOTSET

0

loggingを扱うにあたって、このロギングレベルを知っておかないと「ログが出力されない!」などのトラブルになる場合もあります。
ログが出力されない場合はロガーに設定したロギングレベルを疑ってみましょう。
たとえばロガーのレベルをINFOにした場合は、DEBUGNOTSETなどのログは出力されません。INFOWARNING, ERRORCRITICALは出力されます。

ルートロガーの設定方法(basicConfig)

loggingは我々の見えない所でルートロガーを所持しています(正確に言うと人知れず作成して所持します)。
このルートロガーを設定するにはlogging.basicConfig()を使います。

たとえばルートロガーのロギングレベルをDEBUGにしたい場合は↓のようにします。

logging.basicConfig(level=logging.DEBUG)  # ロギングレベルの設定

↑のようにルートロガーのロギングレベルを設定すると、logging.debug()などでログを出力できるようになります。
levelを設定しない場合はデフォルトでレベルはWARNINGになります。

logging.debug()の使い方

loggingには複数のログを出力する関数がありますが、それらのインターフェースはどれも似ています。
つまりlogging.debug()の仕様を把握すれば、他の関数を使うことが出来ます。

logging.debug()DEBUGレベルのログを出力する関数です。
↓のように使います。

logging.debug('DEBUGです')  # DEBUG:root:DEBUGです

↑のようにdebug()を呼び出すと「DEBUG:root:DEBUGです」というログが出力されます。
デバッグレベルのログの出力はbasicConfig()でロギングレベルをDEBUG以上にしないと出力できないので注意してください。

例外の出力

logging.debug()で例外の内容を出力したい場合は、引数exc_infoTrueを設定します。

try:
    raise ValueError('不正な値です')
except ValueError:
    logging.debug('失敗しました', exc_info=True)
    # DEBUG:root:失敗しました
    # Traceback (most recent call last):
    #   File "/blogsnippets/python/loggingsimple/log.py", line 27, in <module>
    #     raise ValueError('不正な値です')
    # ValueError: 不正な値です

↑のように例外をtry ~ exceptでハンドリングしたときにexc_infoTrueを設定してdebug()を呼び出すと、例外の内容がログに出力されます。

スタックトレースの出力

logging.debug()でスタックトレースを出力したい場合は、引数stack_infoTrueを設定します。

logging.debug('スタックトレースです', stack_info=True)
# DEBUG:root:スタックトレースです
# Stack (most recent call last):
#   File "/blogsnippets/python/loggingsimple/log.py", line 33, in <module>
#     logging.debug('スタックトレースです', stack_info=True)

こちらは簡易的にパスと行数が出力できるので利用されることがあるらしいです。

ログフォーマットの応急的な調整

logging.debug()の引数extraに辞書を指定すると、フォーマット中のその辞書のキーの属性に値を指定できます。

logging.basicConfig(format='%(asctime)-15s: %(myheader)s: %(message)s', level=logging.DEBUG)
logging.debug('デバッグです', extra={ 'myheader': 'ヘッダーです' })
# 2021-01-23 01:23:45,678: ヘッダーです: デバッグです

↑の場合、basicConfig()でログのフォーマットを指定しています。その中でmyheaderというオリジナルな属性を使っています。
debug()myheaderに値を設定することでそれをフォーマットに適用することが出来ます。

その他出力系の関数の使い方

debug()の使い方をマスターしたらあとの関数はその応用でいけます。
以下に一覧を示します。

logging.info('INFOです')  # INFO:root:INFOです
logging.warning('WARNINGです')  # WARNING:root:WARNINGです
logging.error('ERRORです')  # ERROR:root:ERRORです
logging.critical('CRITICALです')  # CRITICAL:root:CRITICALです

try:
    raise ValueError('不正な値です')
except ValueError:
    logging.exception('例外と一緒にログを出力します')
    # ERROR:root:例外と一緒にログを出力します
    # Traceback (most recent call last):
    #   File "/blogsnippets/python/loggingsimple/log.py", line 12, in <module>
    #     raise ValueError('不正な値です')
    # ValueError: 不正な値です

logging.log(logging.DEBUG, 'DEBUGです')  # DEBUG:root:DEBUGです
logging.log(logging.INFO, 'INFOです')  # INFO:root:INFOです

info()INFOレベル、warning()WARNINGレベル、error()ERRORレベル、critical()CRITICALレベルのログを出力します。
また、exception()は例外のハンドリング時に例外も一緒に出力します。レベルはERRORレベルです。

それからlog()は第1引数にロギングレベルを指定できます。

フォーマットの指定

ログのフォーマットの指定はbasicConfig()format引数に指定します。
↓は例と出力です。

logging.basicConfig(
    format='%(levelname)s: %(name)s: %(asctime)s: %(pathname)s: %(funcName)s: %(lineno)d行目: %(message)s'
)

logging.error('エラーです')
# ERROR: root: 2021-01-23 01:23:45,678: /blogsnippets/python/loggingsimple/format.py: <module>: 8行目: エラーです

フォーマット内で使える属性(levelnamenameなど)はあらかじめ予約されています。
それらの属性の一覧は↓から見ることができます。

↑の例で使用している属性の説明は↓になります。

属性名 フォーマット 解説
levelname %(levelname)s ロギングレベルの文字列(DEBUG, ERRORなど)
name %(name)s ロガーの名前
asctime %(asctime)s ログの生成時刻
pathname %(pathname)s ロギング呼び出し時のファイルのパス
funcName %(funcName)s ロギング呼び出し時の関数名
lineno %(lineno)d ロギング呼び出し時の行番号
message %(message)s 引数のメッセージ

ファイルへの出力

ログをファイルに出力したい場合は、basicConfig()の引数filenameにファイルのパスを指定します。

logging.basicConfig(filename='mylog.txt', encoding='utf-8')
logging.error('エラーが発生しました')
# ERROR:root:エラーが発生しました

↑の場合、filenameに指定してmylog.txtにログが出力されます。
また、encodingを指定することでファイルのエンコーディングを指定できます(こちらの引数はPython3.9から)。

おわりに

今回はloggingの使い方を簡単に説明しました。
loggingはわりと学習コストがあるモジュールですが、慣れればすんなり使えそうです。

ログは友達

ログをファイルシステムにシュート!