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,提问作者Олексій Холостенко
相关产品推荐
相关产品推荐

