使用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
相关产品推荐
相关产品推荐

