LoginSignup
14
6

More than 1 year has passed since last update.

【Python】ロギングのベタープラクティス

Last updated at Posted at 2021-05-21

以下の要件を満たすロギングの方法を調べていたのですが、目的の情報が全然見つからなかったので書き残しておくことにしました。
我流ですが"ベストプラクティス"に大きく逸れてはいないと思われます。

要件

  • 生成したloggerは共有
  • コンソールにはINFO以上を出力
  • ファイルにはDEBUG以上を出力
  • ERROR以上のログはメール通知
  • 複数回呼び出したときにログが重複しない

実装

同じ階層にmain.pymy_logger.pyがあるとします。

my_logger.py
import logging
import logging.handlers


def set_logger(module_name):
    logger = logging.getLogger(module_name)
    logger.handlers.clear()

    streamHandler = logging.StreamHandler()
    fileHandler = logging.handlers.RotatingFileHandler("./test.log", maxBytes=10000, backupCount=5)

    formatter = logging.Formatter(
        "%(asctime)s [%(levelname)s] (%(filename)s | %(funcName)s | %(lineno)s) %(message)s")

    streamHandler.setFormatter(formatter)
    fileHandler.setFormatter(formatter)

    logger.setLevel(logging.DEBUG)
    streamHandler.setLevel(logging.INFO)
    fileHandler.setLevel(logging.DEBUG)

    logger.addHandler(streamHandler)
    logger.addHandler(fileHandler)
    logger.addHandler(emailHandler)

    return logger
main.py
import my_logger


logger = my_logger.set_logger(__name__)

logger.debug("debug")
logger.info("info")
logger.warning("warn")
logger.error("error")
logger.critical("critical")

結果

コンソール
$ python /app/tmp/main.py 
2021-05-22 01:21:42,966 [INFO] (main.py | <module> | 7) info
2021-05-22 01:21:42,966 [WARNING] (main.py | <module> | 8) warn
2021-05-22 01:21:45,395 [ERROR] (main.py | <module> | 9) error
2021-05-22 01:21:47,376 [CRITICAL] (main.py | <module> | 10) critical
test.log
2021-05-22 01:21:42,965 [DEBUG] (main.py | <module> | 6) debug
2021-05-22 01:21:42,966 [INFO] (main.py | <module> | 7) info
2021-05-22 01:21:42,966 [WARNING] (main.py | <module> | 8) warn
2021-05-22 01:21:45,395 [ERROR] (main.py | <module> | 9) error
2021-05-22 01:21:47,376 [CRITICAL] (main.py | <module> | 10) critical

my_logger.pyの解説

streamHandler = logging.StreamHandler()
fileHandler = logging.handlers.RotatingFileHandler("./test.log", maxBytes=10000, backupCount=5)

各種ハンドラを定義します。
ログファイルは1MB毎に分割して、直近5つまで保存しておきます。


formatter = logging.Formatter(
    "%(asctime)s [%(levelname)s] (%(filename)s | %(funcName)s | %(lineno)s) %(message)s"
)

streamHandler.setFormatter(formatter)
fileHandler.setFormatter(formatter)
emailHandler.setFormatter(formatter)

ログの形式は好きに設定します。
必要であれば、ハンドラごとにフォーマットを分けることもできます。
例えば、ログファイルはシンプルな形式にするとか。


logger.setLevel(logging.DEBUG)
streamHandler.setLevel(logging.INFO)
fileHandler.setLevel(logging.DEBUG)
emailHandler.setLevel(logging.WARNING)

ここが今回のミソです。
この設定をしなければ、プログラム内で使用しているライブラリによっては、それらのログが混じってしまうことがあります。

ベースレベルはWARNINGに設定されているようです。

print(logging.root.level)

# 30

そこで一旦、logger自体のレベルをDEBUGにし、ルートロガーの設定を上書きします。
これで改めて、子ロガー側からレベルを上書きできます。

14
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
6