[Python] ログレベルでログの出力先を標準出力、標準エラー出力に分ける

概要

Pythonでプログラムを書いているときに、ログ収集プラットフォームに送るログの出力先をログレベルで標準出力、標準エラー出力に分けたいことがあったので、loggingモジュールのフィルタオブジェクトを使って実装する方法を記載します。

この記事で紹介している方法では、それぞれのログレベルの出力先は以下になります。

ログレベル出力先
CRITICAL標準エラー出力
ERROR標準エラー出力
WARNING標準エラー出力
INFO標準出力
DEBUG標準出力

実装

Pythonのloggingモジュールではログレベルを指定することで、指定したレベル以上のレベルのログを出力することができます。

INFOやDEBUGのログレベルを指定すると、よりレベルの高いWARNING, ERROR, CRITICALのログも出力されてしまうので、フィルタを設定して不要なログを除外します。

import logging
import sys


def set_logger(name=None):
    # INFO以下のログを標準出力する
    stdout_handler = logging.StreamHandler(stream=sys.stdout)
    stdout_handler.setLevel(logging.DEBUG)
    stdout_handler.addFilter(lambda record: record.levelno <= logging.INFO)

    # WARNING以上のログを標準エラー出力する
    stderr_handler = logging.StreamHandler(stream=sys.stderr)
    stderr_handler.setLevel(logging.WARNING)

    # ロガーにハンドラを設定する
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    logger.addHandler(stdout_handler)
    logger.addHandler(stderr_handler)


def main():
    set_logger()
    logger = logging.getLogger()

    logger.debug('This is a debug log.')
    logger.info('This is a info log.')
    logger.warning('This is a warning log.')
    logger.error('This is a error log.')
    logger.critical('This is a critical log.')


if __name__ == '__main__':
    main()

動作確認

# DEBUG, INFOログが標準出力に書き込まれている
$ python3 main.py 2> /dev/null
 This is a debug log.
 This is a info log.

# WARNING, ERROR, CRITICALログが標準エラー出力に書き込まれている
$ python3 main.py > /dev/null
 This is a warning log.
 This is a error log.
 This is a critical log.

コメントする