原作者:Django 文档贡献者(原页无个人署名)。本文按 Django 6.1 官方《How to configure and use logging》全文翻译整理,2026 年 10 月 5 日核对。示例锁定该页面版本;实际项目应查看自己安装版本的文档。文中的“预期结果”来自原文说明和配置静态推导,本文没有启动 Django 或执行日志测试。
Django 已提供可扩展的默认日志配置。你可以从一条日志调用开始,逐步配置日志器、处理器、格式化器和命名空间,最后按环境决定需要记录多少信息。理解各层如何衔接,比只复制一份 LOGGING 字典更有帮助。

先发出一条日志
在代码中导入 Python 的 logging 模块,再调用 logging.getLogger() 获取日志器。名称既用于标识日志器,也决定它发出的记录属于哪个命名空间。通常在模块级别使用 __name__,它会产生当前 Python 模块的点分路径。
import logging
logger = logging.getLogger(__name__)
接着在函数内发送记录,例如原文用视图函数示意:
def some_view(request):
...
if some_risky_state:
logger.warning("Platform is running at risk")
这里的 ... 和 some_risky_state 表示省略的业务逻辑,并不是完整可运行的视图。执行到日志调用时,包含消息的 LogRecord 会送入日志器。原文以默认配置下的控制台输出说明 WARNING 级别;项目已有配置、处理器和运行环境可能改变最终去向,排查时须查看实际配置。
严重程度从低到高常用 DEBUG、INFO、WARNING、ERROR、CRITICAL。例如:
logger.critical("Payment system is not responding")
不要期待较低级别的 DEBUG、INFO 默认就显示在控制台;需要为相应日志器及处理器配置级别。
不要在 settings.py 加载期间直接试发日志。Django 在 setup() 流程中完成日志配置,读取设置文件时配置可能尚未就绪。可以在 settings.py 中定义 LOGGING,但用视图、管理命令或其他正常运行时路径观察日志行为。
四类对象各管一件事
- 日志器及其映射(loggers):确定哪些命名空间的记录交给哪些处理器。
- 处理器(handlers):决定记录发往文件、外部服务、邮件或其他目的地,并可单独设置级别。
- 过滤器(filters):提供额外的传递控制,也可以修改记录。原文在这里说明职责,并没有提供一个可直接复制的脱敏过滤器。
- 格式化器(formatters):将
LogRecord转为供人或其他系统消费的文本等形式。
Django 通常通过 LOGGING 设置使用 Python 的 dictConfig 格式。其他配置方式见 Python logging 文档;与 Django 默认配置的关系见 Django logging overview 和 logging reference。下文只使用 LOGGING。
建立最小配置,并保留既有日志器
先在 settings.py 中创建字典:
LOGGING = {
"version": 1, # dictConfig 配置格式版本,不是 Django 版本
"disable_existing_loggers": False,
}
disable_existing_loggers=False 通常是合适的起点,它保留现有日志器供你扩展。若项目有明确的集中日志配置,应结合实际配置关系审查;不要误以为声明一个新字典就意味着所有旧配置都会自动以你预想的方式合并。
配置文件处理器
原文定义一个名为 file 的 logging.FileHandler,将记录写入 general.log:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
},
},
}
处理器类不同,接受的选项也不同。Django 还提供 AdminEmailHandler,Python 标准库也有多种处理器;应按接收方式和部署架构选择。
处理器默认接受交给它的所有级别,但这不代表每条记录都能走到这里。日志器自身的有效级别可能先把记录挡住。若在该处理器的字典中加入 "level": "DEBUG",它便只接受 DEBUG 及以上的记录:
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
}
路径校注:原文把该文件描述为位于项目根目录。这里使用的是相对路径,实际解析依据是运行进程的当前工作目录;从项目根目录启动时二者才一致。部署时建议明确设置一个应用账户可写、访客不可读且不与代码部署互相覆盖的日志路径。
让日志器将记录送到处理器
只定义处理器还不够,还要将它接入日志器。原文使用空字符串键 "" 配置根日志器:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
},
},
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"],
},
},
}
该根配置负责处理传递给根日志器的记录。日志器与处理器是多对多关系,一个日志器可以接多个处理器,同一个处理器也可服务多个日志器。原文以根配置说明“全局收集”;但子日志器的级别、过滤器和 propagate=False 仍可阻止记录到达根部,不能理解为强制捕获所有库的每一条日志。
在能够走到上述配置的应用运行路径中调用:
logger.debug("Attempting to connect to API")
按照原文示例,文件应出现该消息。实际核验时先确认这条代码确实被执行,再检查日志器有效级别、处理器级别、文件路径和写权限。本文未执行该步骤,也没有生成过该日志作为测试证据。
添加格式化器
默认输出通常只含记录的消息文本。需要时间、名称、进程和线程等诊断字段时,可以定义 verbose 与 simple 两个格式化器,再把名称写进处理器的 formatter 选项:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
"formatter": "verbose",
},
},
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"],
},
},
}
这段将原文逐步增加的配置合并展开,便于看清引用关系;两个格式化器都被定义,但 file 使用的是 verbose。字段来自 LogRecord,详见 LogRecord attributes。
原文勘误:Django 6.1 所核对页面把 style 默认值写成 $。Python Formatter 官方签名为 style='%' ;可选值是 %、{、$,分别对应百分号格式、str.format() 与 string.Template。本稿据此修正默认值。该选项控制格式化器的 format 字符串,不会改变 logger.info() 等消息参数本身的格式化规则。
用命名空间管理日志
全局根日志器便于观察,但应用通常需要按来源组织记录。在 my_app/views.py 中调用:
logger = logging.getLogger(__name__)
得到的名称是 my_app.views。若配置 "my_app.views",就能精确控制该模块及其向上传递的子命名空间;配置 "my_app" 则能统一接收该应用内 my_app.views、my_app.utils 等日志器传来的记录。
"loggers": {
"my_app.views": {
"level": "DEBUG",
"handlers": ["file"],
},
}
若希望应用统一接收,则把上例的键改为 "my_app"。这是对应原文两个省略号配置的展开示例;不要把两段重复粘贴并为同一传播链反复挂载同一个处理器,否则可能产生重复记录。
名称也可以显式指定,不必总依赖模块路径:
logger = logging.getLogger("project.payment")
随后以 project.payment 建立相应映射。模块名习惯有助于稳定组织来源、减少无意的名称冲突,但人为给不同模块使用同一名称时,它们仍会共用一个日志器。
理解父子关系与传播
日志器名称是层级结构:my_app 是 my_app.views 的父级,后者又是 my_app.views.private 的父级。默认 propagate=True,记录在本日志器处理后,会继续传给祖先日志器挂载的处理器。
原文通过给最深一级设置 propagate=False 来切断传播。下面保留该关系,并补全可审查的处理器引用:
"loggers": {
"my_app": {
"level": "INFO",
"handlers": ["file"],
},
"my_app.views": {
"level": "DEBUG",
"handlers": [],
},
"my_app.views.private": {
"level": "WARNING",
"handlers": ["file"],
"propagate": False,
},
}
展开说明:这段的具体级别和空处理器列表是编辑为解释传播新增的,原文对应位置使用省略号。它假定 file 已在同一份配置中定义:private 的记录由自己挂载的处理器接收后停止上行,views 的记录可到达 my_app 的处理器。
容易忽略的细节:传播时直接调用祖先的处理器,不会重新执行祖先日志器的级别和过滤器。因此不能靠上例父日志器的 INFO 阈值,保证挡住子日志器已经接受的所有 DEBUG 记录;需要在处理器上设置相应阈值。若根部仍挂着同一 file 处理器,也应审查 my_app 是否继续向根部传播,避免重复写入。配置片段应按自己的日志拓扑选用。
让详细程度随环境变化
调试环境需要的细节,在生产环境可能过量。与其每次手动改设置,不如用受控的环境配置决定级别。原文使用 DJANGO_LOG_LEVEL:
import os
# 放在需要控制的日志器配置中:
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING")
未设置该变量时,默认只接受 WARNING 及以上的记录。处理器的 level 和 formatter 也可按相同思路配置。环境变量是部署配置,应限制可接受值并检查拼写;无效级别可能让日志配置初始化失败。降低日志器级别后,若处理器仍设为 WARNING,DEBUG 依旧不会写入。
把教程配置带入项目之前
原文的 FileHandler 示例没有轮转、压缩、保留期限、磁盘配额或多进程并发策略。长期运行前,应按平台日志收集方式设计这些行为;不要将多个进程对同一文件的写入与轮转假定为天然可靠。相对路径、不可写目录与磁盘耗尽也会造成日志丢失或错误。
根级别设为 DEBUG 可能收集第三方库的详细输出。不得直接记录密码、认证头、访问令牌、会话、支付数据或完整用户请求。先决定业务确实需要哪些字段,再在数据进入日志前脱敏;过滤器提供机制,但“配置了一个过滤器”不自动证明敏感数据已被覆盖。
对于来自外部输入的文本,还需避免换行或控制字符造成伪造日志行。在单行文本格式中可显式规范化这些字符,或采用经过正确编码的结构化日志;普通格式化占位符本身不是日志注入防护。日志配置中的可调用对象和处理器类也应来自可信部署配置,不能把用户提交的任意字典直接交给 dictConfig。
本文静态审查未发现示例中的硬编码秘密,没有执行视图、创建应用日志或验证文件输出。实际验收应在隔离环境分别触发允许与被过滤的级别,确认文件位置、传播、重复记录和脱敏行为;没有发现问题不等于系统无漏洞。
来源及许可:© Django Software Foundation and individual contributors。Django 项目 BSD 3-Clause 许可证的版权、条件和免责声明另存于 LICENSE-Django.txt,随本文示例保留。中文校注与原创示意图:未完纪。
Django 示例代码 BSD 3-Clause 许可全文
Copyright (c) Django Software Foundation and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of Django nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.












暂无评论内容