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

Django项目中Loguru每次启动生成新空日志文件的解决咨询

Django开发环境下Loguru重启生成空日志文件的解决方法

问题背景

在Django项目中使用Loguru作为日志工具,配置了每周轮转、保留1个月的规则,但开发时Django服务器频繁重启导致/logs目录生成大量空日志文件,不符合预期的轮转逻辑。

当前Loguru配置:

from loguru import logger

logger.configure(
    handlers=[
        {
            "sink": "/logs/django_loguru_{time}.log",
            "rotation": "1 week",
            "retention": "1 month",
            "level": "INFO",
        },
    ],
)

对比Python标准logging模块的配置(无空文件问题):

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "d": {"format": "%(asctime)s - %(levelname)s - %(name)s - %(message)s"}
    },
    "handlers": {
        "file": {
            "formatter": "d",
            "level": "WARNING",
            "class": "logging.handlers.TimedRotatingFileHandler",
            "filename": "/logs/django_root.log",
            "when": "D",
            "interval": 7,
            "backupCount": 12,
            "utc": True,
        },
    },
    "root": {
        "handlers": ["file"],
        "level": "WARNING",
    },
}

问题原因

Loguru的sink配置中使用{time}占位符时,会在handler初始化阶段就生成带当前时间戳的文件名并创建文件——哪怕此时没有日志输出。每次Django重启都会重新初始化Loguru handler,因此每次都会生成新的空文件,完全忽略了rotation配置的周期规则。

而标准logging的TimedRotatingFileHandler采用固定主文件名,通过检测文件的最后修改时间判断是否需要轮转,重启时会直接复用未到轮转周期的主文件,不会生成空文件。

解决方案

方案1:改用固定文件名(推荐)

将sink改为固定路径,让Loguru自动处理轮转时的文件重命名逻辑,重启时会复用当前活跃的日志文件,不会生成空文件。

修改后的配置:

from loguru import logger

logger.configure(
    handlers=[
        {
            "sink": "/logs/django_loguru.log",
            "rotation": "1 week",
            "retention": "1 month",
            "level": "INFO",
        },
    ],
)

逻辑说明:

  • Loguru会维护主文件django_loguru.log,所有新日志默认写入该文件
  • 当达到轮转周期(1周)时,Loguru会自动将主文件重命名为带时间戳的归档文件(如django_loguru_2025-04-13_10-40-40.log),并创建新的主文件继续写入
  • 重启时,Loguru会检查主文件的最后修改时间,若未超出轮转周期则直接复用,不会生成新文件

方案2:自定义文件复用逻辑(适合必须保留{time}文件名的场景)

如果业务要求日志文件必须以时间戳命名,可以通过自定义sink函数实现重启时复用最近的有效日志文件:

from loguru import logger
import os
from datetime import datetime, timedelta

def get_recent_log_file():
    log_dir = "/logs"
    prefix = "django_loguru_"
    suffix = ".log"
    recent_file = None
    recent_time = None
    
    # 遍历目录下的日志文件,找到最近的未过期文件
    for filename in os.listdir(log_dir):
        if filename.startswith(prefix) and filename.endswith(suffix):
            try:
                # 解析文件名中的时间戳
                time_str = filename[len(prefix):-len(suffix)]
                file_time = datetime.strptime(time_str, "%Y-%m-%d_%H-%M-%S_%f")
                # 判断是否在轮转周期内(1周)
                if datetime.now() - file_time < timedelta(weeks=1):
                    if recent_time is None or file_time > recent_time:
                        recent_time = file_time
                        recent_file = os.path.join(log_dir, filename)
            except ValueError:
                continue
    
    return recent_file or f"/logs/django_loguru_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S_%f')}.log"

# 配置Loguru使用自定义sink
logger.configure(
    handlers=[
        {
            "sink": get_recent_log_file(),
            "rotation": "1 week",
            "retention": "1 month",
            "level": "INFO",
        },
    ],
)

注意:该方案需要额外处理文件存在性、权限等问题,复杂度较高,非必要不推荐使用。


内容的提问来源于stack exchange,提问作者Олексій Холостенко

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:54:57