やりたかったこと
- 日次のログローテーションの実現
- ローテーション後の拡張子の維持
- コンソール出力とファイル出力の両立
- ログファイルの出力先フォルダの自動作成
ファイル構造
.
├── log.py
├── main.py
└── log
├── application.2026-07-03_23-24-55.log #ローテーションファイル
├── application.2026-07-03_23-24-58.log #ローテーションファイル
├── application.2026-07-03_23-25-01.log #ローテーションファイル
├── application.2026-07-03_23-25-02.log #ローテーションファイル
├── application.2026-07-03_23-26-56.log #ローテーションファイル
└── application.log #直近のログ
ソースコード
main.py
from log import log
from os.path import dirname
from logging import getLogger, INFO, DEBUG
log(dirname(__file__) + '/log', level=INFO) # ログレベル=INFO
logger = getLogger(__name__)
# 下記の例では、DEBUGレベルは出力されない。levelをDEBUGやNOTSETに変えるとDEBUGレベルの出力が可能
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
logger.debug('debug') # 出力しない
log.py
from logging import basicConfig, StreamHandler, getLogger, INFO
from logging.handlers import TimedRotatingFileHandler
from os.path import abspath
from pathlib import Path
class MyTimedRotatingFileHandler(TimedRotatingFileHandler):
def _open(self):
# 存在しないフォルダを作成
Path(self.baseFilename).parent.mkdir(parents=True, exist_ok=True)
return super()._open()
def log(folder, filename='application.log', level=INFO):
# 毎秒ログローテートし、最大5件まで残す
file_handler = MyTimedRotatingFileHandler(
f'{folder}/{filename}', backupCount=5, encoding='utf-8', when='S') # midnightに変えると0時にローテーション
# 拡張子が末尾に移動するように制御
file_handler.namer = lambda fn: fn.replace(
Path(filename).suffix, '') + Path(filename).suffix
# ログのベース設定を定義
basicConfig(
level=level,
format='%(asctime)s [%(levelname)s] %(name)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[
StreamHandler(), # コンソール出力
file_handler # ファイル出力
]
)
# ログ出力先フォルダ表示
getLogger(__name__).info(f'ログ出力先フォルダ: <{abspath(folder)}>')
結果
- 内容はコンソール/ファイル共通
2026-07-03 23:26:59 [INFO] log - ログ出力先フォルダ: <...>
2026-07-03 23:26:59 [INFO] __main__ - info
2026-07-03 23:26:59 [WARNING] __main__ - warning
2026-07-03 23:26:59 [ERROR] __main__ - error
2026-07-03 23:26:59 [CRITICAL] __main__ - critical
参考ページ