pythonによるloggingモジュールの使い方

C#によるlog4netの実装」でC#によるロギング機能をlog4netで実装しましたが、pythonによリ次のロギング機能をloggingモジュールで実装します。

  • ロギングの書式は、タイムスタンプ、モジュール名、ライン番号を付与します。
  • 世代管理を行います。
  • 複数のファイルに分割されたモジュールからのログを一つのログファイルにロギングします。
  • 例外発生時の例外メッセージをロギングします。

二つのファイル「logtest.py」「moduleA.py」に分割したpythonスクリプトを次に示します。

logtest.py

# -*- coding: utf-8 -*-

import logging.config
import moduleA
 
def main():
    # ログ設定ファイルからログ設定を読み込み
    logging.config.fileConfig('logging.conf')
 
    logger = logging.getLogger()
 
    logger.debug('debug')
    logger.info('info')
    logger.warning('warning')
    logger.error('error')
    logger.critical('critical')
 
    moduleA.add(1, 2)

    try:
        1/0
    except Exception as e:
        logging.exception('Exception')

if __name__ == '__main__':
    main()

moduleA.py

import logging.config

# ログ設定ファイルからログ設定を読み込み
logging.config.fileConfig('logging.conf')
 
logger = logging.getLogger()

def add(x, y):
    logger.info( x + y)

ログのレベルを次に示します。このレベルを設定することにより上位のレベルはログされなくなります。

ログのレベル分け
名前 設定値 役割
NOTSET 0 設定値などの記録(全ての記録)
DEBUG 10 動作確認などデバッグの記録
INFO 20 正常動作の記録
WARNING 30 警告の記録
ERROR 40 エラーなど重大な問題
CRITICAL 50 停止など致命的な問題

ロギングの設定ファイル「logging.conf」を次に示します。

logging.conf

[loggers]
keys=root
 
[handlers]
keys=consoleHandler, fileHandler
 
[formatters]
keys=logFormatter
 
[logger_root]
level=DEBUG
handlers=consoleHandler, fileHandler
 
[handler_consoleHandler]
class=logging.StreamHandler
formatter=logFormatter
args=(sys.stdout, )
 
[handler_fileHandler]
class=handlers.RotatingFileHandler
formatter=logFormatter
args=('./log/test.log','a', (100), 3)
 
[formatter_logFormatter]
class=logging.Formatter
format=%(asctime)s %(filename)s:%(lineno)d %(message)s

設定ファイルには次の項目が必要になります。

  • [loggers] 「keys=」の後に任意のlogger名を記述。「root」は必須。
  • [handlers] 「keys=」の後に任意のhandler名を記述。
  • [formatters] 「keys=」の後に任意のformatter名を記述。

次に「keys=」で定義したlogger名、handler名、formatter名を記述していきます。
[logger_logger名] ロガーにハンドラーの追加
[handler_handler名] ハンドラーの設定
[formatter_formatter名] フォーマッターの設定

作成したpythonスクリプトを次のコマンドで実行します。フォルダ「log」のファイル「test.log」に表示されたログと同じ内容が記録されます。

$ python3 logtest.py
2017-12-12 07:55:43,107 logtest.py:12 debug
2017-12-12 07:55:43,113 logtest.py:13 info
2017-12-12 07:55:43,114 logtest.py:14 warning
2017-12-12 07:55:43,114 logtest.py:15 error
2017-12-12 07:55:43,115 logtest.py:16 critical
2017-12-12 07:55:43,115 moduleA.py:9 3
2017-12-12 07:55:43,116 logtest.py:23 Exception
Traceback (most recent call last):
File “logtest.py”, line 21, in main
1/0
ZeroDivisionError: division by zero

ロギングの書式

次のロギングの書式により、タイムスタンプ、モジュール名、ライン番号をログメッセージに付与します。

format=%(asctime)s %(filename)s:%(lineno)d %(message)s

そのほかに設定できる項目を次に示します。

ログの出力フォーマット
フォーマット 役割
%(asctime)s 実行時刻
%(filename)s ファイル名
%(funcName)s 行番号
%(levelname)s ログの定義
%(lineno)d ログレベル名
%(message)s ログメッセージ
%(module)s モジュール名
%(name)s 関数名
%(process)d プロセスID
%(thread)d スレッドID

世代管理

世代管理は、次に示すログのローテート機能を使います。

class=handlers.RotatingFileHandler
args=(‘./log/test.log’,'a’, (100), 3)

書式を次に示します。

class logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
 maxBytes:1ファイルにログする最大バイト数
 backupCount:世代数

そのほかに、特定の時間間隔により分割する次のローテート設定「TimedRotatingFileHandler」もあります。

class logging.handlers.TimedRotatingFileHandler(filename, when=’h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)

次に、実際に世代管理されたファイル群、3ファイルを示します。最新のログは「test.log」に保存されます。

世代管理

複数ファイルに渡るロギング

複数のファイルに分割されたモジュールからのログを一つのログファイルにロギングします。これは特に意識せずに、次のようにファイルごとに再宣言すれば同じログファイルに追加されていきます。

import logging.config
 
logging.config.fileConfig('logging.conf')
logger = logging.getLogger()

例外メッセージのロギング

例外発生時の例外メッセージは、次の関数「logging.exception」を使用してロギングします。

try:
    ・・・
except Exception as e:
    logging.exception('Exception')