完成形
年月ごとにログファイルがまとまります
LOG_DIR
├── 2025
│ ├── 01
│ │ ├── LOG_FILE.20250101.log
│ │ ├── ...
│ │ └── LOG_FILE.20250131.log
│ └── 02
│ ├── LOG_FILE.20250201.log
│ ├── ...
│ └── LOG_FILE.20250228.log
└── LOG_FILE
実装
TimedRotatingFileHandlerを継承したハンドラを作成します
サンプルコード
import re
import time
from datetime import datetime
from logging import getLogger
from logging.handlers import TimedRotatingFileHandler
from pathlib import Path
class MyTimedRoatingFileHandler(TimedRotatingFileHandler):
def __init__(
self,
filename,
when="h",
interval=1,
backupCount=0,
encoding=None,
delay=False,
utc=False,
atTime=None,
errors=None,
):
super().__init__(
filename, when, interval, backupCount, encoding, delay, utc, atTime, errors
)
# 日時の「-」と「_」を取り除く
self.suffix = re.sub(r"([-_])", "", self.suffix)
extMatch = re.sub(r"([-_])", "", self.extMatch.pattern)
self.extMatch = re.compile(extMatch, re.ASCII)
def rotation_filename(self, default_name):
# default_nameから日時を取り出す
dt_str = self.extMatch.findall(default_name)[-1]
dt = datetime.strptime(dt_str, self.suffix)
# 日時を使ってfilenameを変更する
default_name_path = Path(default_name)
default_name = (
default_name_path.parent
/ dt.strftime("%Y")
/ dt.strftime("%m")
/ default_name_path.name
)
return super().rotation_filename(default_name)
def rotate(self, source, dest):
# 存在しないディレクトリは作成する
Path(dest).parent.mkdir(parents=True, exist_ok=True)
return super().rotate(source, dest)
def _open(self):
# 存在しないディレクトリは作成する
Path(self.baseFilename).parent.mkdir(parents=True, exist_ok=True)
return super()._open()
logger = getLogger()
handler = MyTimedRoatingFileHandler("LOG_DIR/LOG_FILE", "S") # 実運用はwhen="midnight"とします
handler.namer = lambda default_name: f"{default_name}.log"
logger.addHandler(handler)
# ログを出力してみる
for i in range(20):
logger.error("ERROR MESSAGE")
time.sleep(0.5)