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関数を利用することでログの内容とエラー内容を把握して開発効率や運用保守の効率化を実現することができます。
コメント