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

FastAPI项目如何通过config.ini配置日志按大小和时间双重轮转?

实现同时按大小和时间轮转日志

Python标准库的logging模块没有内置同时支持大小轮转和时间轮转的Handler,你需要自定义一个Handler来结合两种轮转逻辑,或者使用第三方库。下面是自定义Handler的实现方案:

步骤1:自定义轮转Handler

在你的FastAPI项目的api目录下创建log_handlers.py文件,写入以下代码:

import logging
from logging.handlers import RotatingFileHandler
import os
import time

class SizeAndTimeRotatingFileHandler(RotatingFileHandler):
    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False, when='s', interval=1, utc=False):
        # 初始化大小轮转相关参数
        super().__init__(filename, mode, maxBytes, backupCount, encoding, delay)
        # 初始化时间轮转相关参数
        self.when = when.upper()
        self.interval = interval
        self.utc = utc
        # 日志文件后缀格式(按秒轮转的话,精确到秒)
        self.suffix = "%Y-%m-%d_%H-%M-%S"
        # 计算下一次轮转的时间点
        if os.path.exists(filename):
            self.rolloverAt = self.compute_rollover_time(os.path.getmtime(filename))
        else:
            self.rolloverAt = self.compute_rollover_time(time.time())

    def compute_rollover_time(self, current_time):
        # 计算下一次时间轮转的时间点(这里仅实现秒级轮转,可扩展其他时间单位)
        if self.when == 'S':
            rollover_seconds = self.interval
            current_time = current_time - (current_time % rollover_seconds) + rollover_seconds
        return current_time

    def shouldRollover(self, record):
        # 同时判断两个轮转条件:大小达标 或 时间到点
        size_trigger = super().shouldRollover(record)
        time_trigger = time.time() >= self.rolloverAt
        return size_trigger or time_trigger

    def doRollover(self):
        # 执行轮转操作:重命名当前日志文件,生成带时间后缀的备份
        if self.stream:
            self.stream.close()
            self.stream = None
        
        # 生成带时间后缀的备份文件名
        current_time = time.time()
        time_str = time.strftime(self.suffix, time.gmtime(current_time) if self.utc else time.localtime(current_time))
        backup_filename = f"{self.baseFilename}.{time_str}"
        
        if os.path.exists(backup_filename):
            os.remove(backup_filename)
        os.rename(self.baseFilename, backup_filename)

        # 删除超过备份数量限制的旧日志
        if self.backupCount > 0:
            for old_file in self.getFilesToDelete():
                os.remove(old_file)
        
        # 更新下一次时间轮转的时间点
        self.rolloverAt = self.compute_rollover_time(current_time)
        
        # 重新打开新的日志文件
        if not self.delay:
            self.stream = self._open()

步骤2:修改日志配置文件logconfig.ini

更新handler_logfile部分,指定自定义Handler的类路径,并传入你的参数(大小限制500字节,10秒轮转,备份数1000):

[loggers]
keys=root

[handlers]
keys=logfile

[formatters]
keys=logfileformatter

[logger_root]
level=INFO
handlers=logfile

[formatter_logfileformatter]
format=[%(asctime)s.%(msecs)03d] %(levelname)s [%(thread)d] - %(message)s

[handler_logfile]
class=api.log_handlers.SizeAndTimeRotatingFileHandler
args=('C:\\path\\api.log', 'a', 500, 1000, None, False, 's', 10, False)

参数说明:

  • 'C:\\path\\api.log': 日志文件路径
  • 'a': 写入模式(追加)
  • 500: 单文件最大字节数
  • 1000: 最大备份文件数
  • None: 编码(默认None)
  • False: 是否延迟打开文件
  • 's': 时间轮转单位(秒,可选值:S/秒、M/分、H/时、D/天等)
  • 10: 时间轮转间隔(10秒)
  • False: 是否使用UTC时间

步骤3:移除冲突的日志配置

删除main.py中的logging.basicConfig代码块,因为你已经通过--log-config指定了日志配置,重复配置会导致日志重复输出或冲突:

# 删掉这段代码
# logging.basicConfig(
#     level=logging.INFO,
# )

可选方案:使用第三方库

如果你不想自定义Handler,可以使用第三方库concurrent-log-handler,它支持同时按大小和时间轮转:

  1. 安装库:
pip install concurrent-log-handler
  1. 修改logconfig.ini的handler_logfile部分:
[handler_logfile]
class=concurrent_log_handler.ConcurrentRotatingFileHandler
args=('C:\\path\\api.log', 'a', 500, 1000)
kwargs={"when": "S", "interval": 10}

内容的提问来源于stack exchange,提问作者Hannon qaoud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:27:41