Pythonでログファイルをローテーション出力する|デバッグが楽に。

Python

Pythonでログファイルをローテーション出力するには?

Pythonではlogging.handlers.RotatingFileHandlerを使うことでプログラムで発生したログを出力することが可能です。本記事では、Pythonでログを出力するout_log関数を作成してエラーレベルごとで出力する手順を紹介します。

out_log関数のサンプルコード

まずは、out_log関数のサンプルコードを紹介します。サンプルコードを利用したい場合にはlog_util.pyで保存ください。

import logging.handlers
import inspect
import traceback

# 定数 ログファイル名、サイズ、バックアップ世代数、ログレベルを設定
LOG_FILE_NAME = 'debug.log' #ログファイル名 c:\\hoge\\debug.log等も指定可能
LOG_FILE_SIZE = 1024        #ログファイルサイズ バイト単位指定
LOG_BACKUP_COUNT = 5        #バックアップ世代数
LOG_LEVEL = 'WARNING'       #ログレベル DEBUG, INFO, WARNING, ERROR, CRITICAL


# ロガーの設定
logger = logging.getLogger()
logger.setLevel(LOG_LEVEL) #ログファイル出力のレベルを変更できる。

# ログファイルの設定
handler = logging.handlers.RotatingFileHandler(
    LOG_FILE_NAME, maxBytes=LOG_FILE_SIZE, backupCount=LOG_BACKUP_COUNT, encoding='utf-8'
)

# ログのフォーマット設定
formatter = logging.Formatter("[%(levelname)s] %(asctime)s %(message)s ")
handler.setFormatter(formatter)

# ロガーにハンドラを追加
logger.addHandler(handler)


def out_log(msg, level=1):
    """
    ログを出力する

    Parameters
    ----------
    msg : str
        出力するメッセージ
    level : int, optional
        ログレベル(1:DEBUG, 2:INFO, 3:WARNING, 4:ERROR, 5:CRITICAL), デフォルトは 1
    """
    # ログの出力
    callerframerecord = inspect.stack()[1]  # 呼び出し元の情報を取得する
    filename = callerframerecord[0].f_code.co_filename
    lineno = callerframerecord[0].f_lineno
    if level == 1:
        logger.debug(f'{filename}:{lineno} \n {traceback.format_exc()} {msg} ')
    elif level == 2:
        logger.info(f'{filename}:{lineno} \n {traceback.format_exc()} {msg} ')
    elif level == 3:
        logger.warning(f'{filename}:{lineno} \n {traceback.format_exc()} {msg} ')
    elif level == 4:
        logger.error(f'{filename}:{lineno} \n {traceback.format_exc()} {msg} ')
    elif level == 5:
        logger.critical(f'{filename}:{lineno} \n {traceback.format_exc()} {msg} ')

    # ターミナル出力 不要な場合にはコメントアウト
    print(msg)

5行目から8行目は定数となっています。

LOG_FILE_NAME ログファイルの名前です。

LOG_FILE_SIZE ログファイルのサイズです、このバイト数を超えるとログファイルがローテションします。

LOG_BACKUP_COUNT バックアップ世代数でLOG_FILE_SIZEを超えると新たなファイルが作成されます。例えばdebug.logが1024バイトを超えた場合debug.log.1というファイルにバックアップされ、指定世代までローテーションされてログファイルによるディスク枯渇を防ぐことが可能です。
今回の例ではdebug.log.5まで作成されるとそれ以降はファイルが消去されます。

LOG_LEVEL ログレベルが DEBUG, INFO, WARNING, ERROR, CRITICALのどのレベル以上を出力するか指定します。例えばWARNINGを指定した場合にはWARNING, ERROR, CRITICALのログが出力されます。

定数なので、iniファイルから取得する方法でも良いでしょう。

out_log関数の使用例その1

以下のサンプルコードは、out_log関数の動作を確認するための例です。

from log_util import out_log

out_log("DEBUG    メッセージ",1)
out_log("INFO     メッセージ",2)
out_log("WARNING  メッセージ",3)
out_log("ERROR    メッセージ",4)
out_log("CRITICAL メッセージ",5)

コンソールの実行結果は以下の通りです。

DEBUG    メッセージ
INFO     メッセージ
WARNING  メッセージ
ERROR    メッセージ
CRITICAL メッセージ
DEBUG    メッセージ
INFO     メッセージ
WARNING  メッセージ
ERROR    メッセージ
CRITICAL メッセージ

debug.logの中身は以下のようになります。
log_util.pyの10行目にLOG_LEVELでWARNINGを指定しているので、debug.logにはWARNING以上が出力されます。

[WARNING] 2023-08-07 17:32:19,744 c:\Users\wkusr\Documents\pycode\TEST.py:5 
 NoneType: None
 WARNING  メッセージ  
[ERROR] 2023-08-07 17:32:19,746 c:\Users\wkusr\Documents\pycode\TEST.py:6 
 NoneType: None
 ERROR    メッセージ  
[CRITICAL] 2023-08-07 17:32:19,747 c:\Users\wkusr\Documents\pycode\TEST.py:7 
 NoneType: None
 CRITICAL メッセージ  

out_log関数の使用例その2

以下のサンプルコードは、out_log関数を例外エラーを発生させた場合の確認例です。

from log_util import out_log

def a():
    b()

def b():
    char = None
    char.format('hogehoge') #Noneをフォーマットしてエラー発生させる。

try:
    a()
except Exception as e:
    out_log(e,5) #CRITICAL で出力する。

コンソールの実行結果は以下の通りです。

'NoneType' object has no attribute 'format'

debug.logの中身は以下のようになります。
log_util.pyのログ出力時にtraceback.format_exc()を記載しているため、エラー箇所を行番号で追うことが可能です。

[CRITICAL] 2023-08-07 17:37:46,288 c:\Users\wkusr\Documents\pycode\TEST_ERROR.py:13 
 Traceback (most recent call last):
  File "c:\Users\wkusr\Documents\pycode\TEST_ERROR.py", line 11, in <module>
    a()
  File "c:\Users\wkusr\Documents\pycode\TEST_ERROR.py", line 4, in a
    b()
  File "c:\Users\wkusr\Documents\pycode\TEST_ERROR.py", line 8, in b
    char.format('hogehoge') #Noneをフォーマットしてエラー発生させる。
    ^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'format'
 'NoneType' object has no attribute 'format'  

最後に

以上がPythonでログをローテーション出力する手順です。

Pythonではログを出力する方法はいろいろありますが、out_log関数を利用することでログの内容とエラー内容を把握して開発効率や運用保守の効率化を実現することができます。

コメント

タイトルとURLをコピーしました