You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python logging模块归档旧日志文件的问题

使用Python logging模块归档旧日志文件的问题

我完全懂你现在的困扰——用RotatingFileHandler默认只会生成带数字后缀的轮替日志(比如app.log.1),但你想给归档的旧日志加上归档日期,直接改扩展名肯定行不通,官方文档里也没直接给出现成的配置项对吧?之前找到的2011年的自定义类方案可能因为Python版本迭代有点过时了,那咱们来调整出一个适配现在Python 3.x版本的解决方案。

核心思路其实很简单:继承RotatingFileHandler,重写它的doRollover方法——这个方法负责处理日志文件滚动的逻辑,我们可以在里面把默认的数字后缀替换成日期戳。

下面是修改后的完整代码,我会标注关键改动:

import logging
import os
import datetime
import logging.handlers

log_dir = 'logs'
if not os.path.exists(log_dir):
    os.makedirs(log_dir)

class DateRotatingFileHandler(logging.handlers.RotatingFileHandler):
    def doRollover(self):
        # 先关闭当前的日志文件,避免占用
        if self.stream:
            self.stream.close()
            self.stream = None
        
        # 获取当前归档的日期时间,格式可以自己调整
        now = datetime.datetime.now()
        date_str = now.strftime("%Y%m%d_%H%M%S")
        
        # 构建归档后的文件名
        base_filename = self.baseFilename
        archive_filename = f"{os.path.splitext(base_filename)[0]}_{date_str}{os.path.splitext(base_filename)[1]}"
        
        # 如果归档文件已经存在,可以加个序号避免覆盖(可选)
        counter = 1
        while os.path.exists(archive_filename):
            archive_filename = f"{os.path.splitext(base_filename)[0]}_{date_str}_{counter}{os.path.splitext(base_filename)[1]}"
            counter += 1
        
        # 重命名旧日志文件为归档文件名
        if os.path.exists(base_filename):
            os.rename(base_filename, archive_filename)
        
        # 重新打开新的日志文件
        self.mode = 'w'
        self.stream = self._open()

def get_logger(name):
    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)
    
    max_bytes = 100 * 1024 * 1024  # 100 Mb
    # 替换成咱们自定义的Handler
    file_handler = DateRotatingFileHandler(
        filename=f'{log_dir}/{name}.log',
        maxBytes=max_bytes,
        encoding='utf-8'
    )
    file_handler.setLevel(logging.INFO)
    
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.ERROR)
    
    f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    file_handler.setFormatter(f_format)
    
    c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(c_format)
    
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)
    
    # 避免重复添加Handler(如果多次调用get_logger的话)
    if len(logger.handlers) > 2:
        logger.handlers = logger.handlers[:2]
    
    return logger

# 测试一下
if __name__ == "__main__":
    logger = get_logger("test_app")
    for _ in range(100000):
        logger.info("这是一条测试日志")

关键改动说明:

  • 自定义了DateRotatingFileHandler,重写doRollover方法:
    • 关闭当前日志流,避免文件被占用
    • 生成带日期时间的归档文件名(格式是YYYYMMDD_HHMMSS,你可以根据需求调整,比如改成YYYY-MM-DD)
    • 处理归档文件重名的情况(可选,避免覆盖已有文件)
    • 重命名旧日志为归档文件,然后重新打开新的日志文件
  • 在get_logger函数里,把原来的RotatingFileHandler替换成自定义的DateRotatingFileHandler
  • 加了一段避免重复添加Handler的逻辑(如果多次调用get_logger会导致日志重复输出)

这样当日志文件达到100MB时,就会自动把旧日志重命名成类似test_app_20240520_143022.log的格式,而不是默认的数字后缀了。

如果你不需要处理重名的情况,可以把那段循环判断的代码删掉,简化归档逻辑。另外,日期格式也可以根据你的需求调整,比如用%Y-%m-%d生成test_app_2024-05-20.log这样的文件名。

备注:内容来源于stack exchange,提问作者BDBazuso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 09:33:01