不能只用一个logging配置块统一处理两类日志,因为logging层级机制和propagate行为会导致访问日志意外触发错误处理器;django.request仅在异常时记录带traceback的日志,django.server则每请求都记录不含traceback的简明信息;需为自定义logger显式设propagate=false,并用filter(如拦截2xx/3xx)分离访问与错误日志,同时注意文件权限、轮转配置及systemd干扰。

为什么不能只用一个 LOGGING 配置块统一处理两类日志
因为 logging 的层级机制和 propagate 行为会让访问日志意外触发错误处理器——比如你给 django.request 单独配了 access_file,但它的父 logger 是 django,默认 propagate=True,结果请求 404 也会被写进 error 日志文件。这不是配置漏了,是传播逻辑没关。
- 所有自定义 logger 必须显式设
propagate=False -
django.request和django.server是访问日志主力,但它们不捕获 5xx;5xx 实际由django根 logger 或django.core.handlers.exception发出 - 错误日志建议绑定到
django(覆盖全局异常)或更细粒度的django.db、django.security
如何让 access.log 只记录 2xx/3xx 请求且不含 traceback
靠 handler 的 level 不够——INFO 级别下 django.server 仍会输出 404/500。得用 Filter 拦截非成功响应。
- 写一个轻量 filter:
class AccessLogFilter: def filter(self, record): return record.status_code in (200, 301, 302, 304) - 在
LOGGING中注册它:'filters': {'access_only': {'()': 'path.to.AccessLogFilter'}} - 把 filter 绑到
access_handler,同时确保该 handler 的level设为INFO(django.server默认发 INFO 级日志) - 别忘了给
django.serverlogger 设propagate=False,否则它还会往上扔给 root logger
django.request 和 django.server 的日志内容差异在哪
django.request 只在发生异常(400/500)时触发,带完整 traceback;django.server 则每条 HTTP 请求都记一条,含状态码、耗时、method、path,但不带 traceback。想分清楚访问和报错,优先盯 django.server + filter,而不是依赖 django.request。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
-
django.request的典型 message:"Internal Server Error: /api/user/",后面紧接 traceback -
django.server的典型 message:"GET /api/user/ HTTP/1.1 200 1234",无堆栈 - 若要记录所有请求(含 4xx/5xx)但不混入错误日志,就用
django.server+ 更宽松的 filter(比如只排除 5xx)
文件路径权限和轮转配置容易忽略的坑
Django 启动用户(如 www-data)必须对日志目录有写权限,否则 handler 初始化失败,日志静默丢失——连 warning 都不会打。另外 RotatingFileHandler 的 maxBytes 和 backupCount 要配合磁盘空间预估,否则可能撑爆分区。
- 日志路径用绝对路径,避免相对路径在不同启动方式(manage.py vs gunicorn)下解析错位
- 推荐用
TimedRotatingFileHandler按天轮转,比按大小更可控:'when': 'midnight', 'interval': 1, 'backupCount': 30 - 如果用 systemd 管理 Django 进程,确保
StandardOutput=journal不干扰文件 handler,必要时关掉consolehandler
最麻烦的其实是 filter 的编写和 propagate 开关——调通前先开个临时 console handler 打印 logger.name 和 level,不然根本不知道哪条日志从哪个 logger 出来的。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










