Django 3.2.14应用日志未轮转问题排查求助
Django日志未轮转的原因分析及解决办法
核心问题:Gunicorn多进程的文件句柄冲突
你的Gunicorn开了9个工作进程,每个worker都会单独初始化Django的日志配置,这就导致多个进程同时攥着同一个日志文件的句柄。当TimedRotatingFileHandler尝试轮转日志时,只有一个进程能完成文件重命名,但其他进程还在往旧的文件句柄里写数据——结果就是新日志文件没生成,旧文件一直变大,看起来完全没轮转。这绝对和Gunicorn的多进程有关,是这类部署场景下的常见坑。
其他可能的诱因
- 日志目录权限不够:
logs目录的权限得让ubuntu用户(Gunicorn运行用户)能创建、重命名文件。比如目录属于www-data组但没开组写入权限,或者ubuntu用户根本没权限操作这个目录,轮转操作直接失败,自然看不到效果。- 查权限用命令:
ls -ld logs/,确保权限是类似drwxrwxr-x ubuntu www-data这种,让ubuntu有读写权限。
- 查权限用命令:
- 轮转周期设置太长:你配置的
interval=30+when="D"是30天才轮转一次,要是部署时间还没到30天,自然不会触发。测试的话可以改成when="M"(按分钟轮转),等几分钟看效果。 - 缺省
backupCount参数:虽然这个参数只是控制保留旧日志的数量,默认0是不删除旧日志,但如果没设置,部分场景下可能影响轮转文件的生成逻辑,建议加上试试。
针对性解决办法
1. 用系统级logrotate管理(最推荐)
放弃Django自带的轮转逻辑,用Linux系统的logrotate来管日志,彻底规避多进程冲突问题:
- 创建配置文件
/etc/logrotate.d/django-app,内容如下:/path/to/your/app/logs/app /path/to/your/app/logs/groups { daily rotate 30 missingok notifempty compress delaycompress create 660 ubuntu www-data sharedscripts postrotate # 给Gunicorn发USR1信号,让所有worker重新打开日志文件 pkill -USR1 gunicorn endscript } - 手动测试执行:
logrotate -f /etc/logrotate.d/django-app,看看日志会不会轮转。
2. 用多进程安全的日志Handler
安装concurrent-log-handler包,它专门解决多进程下的日志轮转问题:
- 安装命令:
pip install concurrent-log-handler - 修改Django的
LOGGING配置里的handler:"app": { "level": "INFO", "class": "concurrent_log_handler.ConcurrentRotatingFileHandler", "formatter": "elegant", "filename": os.path.join("logs", "app"), "maxBytes": 10485760, # 单个日志文件最大10MB "backupCount": 30, # 保留30个旧日志 "encoding": "utf-8", }, "groups": { "level": "INFO", "class": "concurrent_log_handler.ConcurrentRotatingFileHandler", "formatter": "elegant", "filename": os.path.join("logs", "groups"), "maxBytes": 10485760, "backupCount": 30, "encoding": "utf-8", },
3. 调整Gunicorn启动参数
别用--preload参数,因为--preload会在fork worker之前就加载Django,导致所有worker共享同一个日志文件句柄,加剧冲突。确保Gunicorn是每个worker单独加载Django和日志配置。
内容的提问来源于stack exchange,提问作者Diego Carabajal
相关产品推荐
相关产品推荐

