たれながし.info

とあるITエンジニアの備忘録

Pythonの「logging」で画面とファイル両方にログ出力

Pythonの標準モジュール「logging」で画面とファイル両方にログ出力する方法

はじめに

Pythonには「logging」という、ログ出力のための標準モジュールがあることを知ったので使ってみました。
(ログをprintで画面出力、open→writeでファイル出力するよりは便利です。)

また、「logging」のデフォルト設定ではログを画面に出力するのみなので、
画面とファイル両方に同時出力する方法を調べてみました。

loggingについて

「logging」のマニュアルは以下となります。
docs.python.org

loggingの動作確認

loggingでどんなことができるのか確認してみました。

デフォルト設定でのログ出力

import logging

logging.critical("This is Critical.")
logging.error("This is Error.")
logging.warning("This is Warning.")
logging.info("This is Info.")
logging.debug("This is Debug.")


<実行結果>
デフォルト設定ではログレベルのWarning以上が画面に出力されます。
rootは「root階層にあるロガー」を意味しています。

CRITICAL:root:This is Critical.
ERROR:root:This is Error.
WARNING:root:This is Warning.

ファイルへの出力

Debug以上のログをファイル出力する例となります。

basicConfigメソッドは基本的な環境設定を行うメソッドです。
basicConfigメソッドで設定できる項目は他のメソッド(setLevelなど)でも設定可能です。

import logging

logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)

ログフォーマットの設定

ログフォーマットはbasicConfigメソッドの引数「format」で設定します。
setFormatterメソッドでも設定できます。

import logging

logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s')
logging.warning('is when this event was logged.')


<実行結果>

2022-08-22 01:10:49,044:WARNING:is when this event was logged.

ログローテート

「RotatingFileHandler」はファイルサイズ、「TimedRotatingFileHandler」は時間でログローテートできます。

import logging
import logging.handlers

rh = logging.handlers.RotatingFileHandler(filename="test.log", maxBytes=1000, backupCount=3)
formatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")
rh.setFormatter(formatter)

logger = logging.getLogger()
logger.addHandler(rh)

while True:
    logger.warning("This is Warning.")


<実行結果>
上記例だと、1000バイトでローテートされ、現在のログ含め4世代残ります。

> ls test.log*

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2022/03/01     23:21              0 test.log
-a----        2022/03/01     23:21            990 test.log.1
-a----        2022/03/01     23:21            990 test.log.2
-a----        2022/03/01     23:21            990 test.log.3

画面とファイル両方にログ出力

下記条件で、画面とファイル両方にログ出力する例です。

  • ログフォーマットは時間、ログレベル、メッセージを指定
  • ログレベルinfo以上を記録
  • 画面とファイル両方に出力
  • ファイルは追記モード、文字コードutf-8

流れとしては、まずgetLoggerでrootロガーを取得し、ログレベルを設定します。
その後、画面出力用(StreamHandler)とファイル出力用(FileHandler)のそれぞれのハンドラーを作成し、ログフォーマットを設定の上、ロガーに追加します。

import logging

# ロガーの取得、ログレベル設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# ログフォーマット
logFormatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')

# 画面出力設定
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
logger.addHandler(consoleHandler)

# ファイル出力設定
fileHandler = logging.FileHandler("test.log", mode="a", encoding="utf_8")
fileHandler.setFormatter(logFormatter)
logger.addHandler(fileHandler)

# ログ出力
logger.info("This is info")