日志

Django 的日志模块扩展了 Python 内置的 logging

日志记录是作为 Django 的通用 django.setup() 函数的一部分进行配置的,因此除非明确禁用,否则始终可用。

Django 的默认日志配置

默认情况下,Django 使用 Python 的 logging.config.dictConfig 格式

默认的日志记录条件

完整的默认日志记录条件如下:

DEBUGTrue 时:

  • django 记录器将 django 层次结构(django.server 除外)中的 INFO 级别或更高的消息发送到控制台。

DEBUGFalse 时:

  • django 记录器将 django 层次结构(django.server 除外)中带有 ERRORCRITICAL 级别的消息发送到 AdminEmailHandler

无论 DEBUG 的值如何:

  • django.server 记录器向控制台发送 INFO 或更高等级的消息。

除了 django.server 之外,所有的日志记录器都会将日志记录传播给它们的父辈,直到 django 的根日志记录器。consolemail_admins 处理程序被附加到根记录器上,以提供上述行为。

Python 的默认设置会将级别为 WARNING 及更高级别的记录发送到控制台。

默认的日志定义

Django 的默认日志配置继承了 Python 的默认设置。它以 django.utils.log.DEFAULT_LOGGING 的形式可用,并在 django/utils/log.py 中定义如下:

{
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {
        "require_debug_false": {
            "()": "django.utils.log.RequireDebugFalse",
        },
        "require_debug_true": {
            "()": "django.utils.log.RequireDebugTrue",
        },
    },
    "formatters": {
        "django.server": {
            "()": "django.utils.log.ServerFormatter",
            "format": "[{server_time}] {message}",
            "style": "{",
        }
    },
    "handlers": {
        "console": {
            "level": "INFO",
            "filters": ["require_debug_true"],
            "class": "logging.StreamHandler",
        },
        "django.server": {
            "level": "INFO",
            "class": "logging.StreamHandler",
            "formatter": "django.server",
        },
        "mail_admins": {
            "level": "ERROR",
            "filters": ["require_debug_false"],
            "class": "django.utils.log.AdminEmailHandler",
        },
    },
    "loggers": {
        "django": {
            "handlers": ["console", "mail_admins"],
            "level": "INFO",
        },
        "django.server": {
            "handlers": ["django.server"],
            "level": "INFO",
            "propagate": False,
        },
    },
}

请参阅 日志模块的配置 了解如何补充或替换此默认日志配置。

Django 日志扩展

Django 提供了许多工具来处理在 Web 服务器环境中的日志记录特定要求。

Loggers

Django 提供了几种内置的记录器。

django

django 命名的日志层次结构 中,用于消息的父日志记录器。Django 不使用这个名称发布消息。而是使用以下其中一个日志记录器。

django.request

记录与处理请求有关的信息。5XX 的响应以 ERROR 消息的形式出现;4XX 的响应以 WARNING 消息的形式出现。记录在 django.security 记录器中的请求不会记录在 django.request 中。

发送给此记录器的消息有以下额外的上下文:

  • status_code:与请求相关的 HTTP 响应代码。

  • request:产生记录信息的请求对象。

django.server

记录与处理由 runserver 命令调用的服务器收到的请求有关的消息。HTTP 5XX 响应被记录为 ERROR 消息,4XX 响应被记录为 WARNING 消息,其他所有消息被记录为 INFO

发送给此记录器的消息有以下额外的上下文:

  • status_code:与请求相关的 HTTP 响应代码。

  • request:生成日志消息的请求对象(一个 socket.socket)。

django.template

记录与模板渲染相关的消息。

  • 缺少的上下文变量会被记录为 DEBUG 消息。

django.db.backends

与代码与数据库互动有关的信息。例如,请求执行的每一条应用程序级别的 SQL 语句都会以 DEBUG 级别记录到这个记录器。

发送给此记录器的消息有以下额外的上下文:

  • duration:执行 SQL 语句所需时间。

  • sql:所执行的 SQL 语句。

  • params:SQL 调用中使用的参数。

  • alias:SQL 调用中使用的数据库的别名。

出于性能考虑,只有当 settings.DEBUG 设置为 True 时,才会启用 SQL 日志记录,而不考虑日志级别或安装的处理程序。

这个日志记录不包括框架级别的初始化(例如 SET TIMEZONE)。如果希望查看所有数据库查询,请在数据库中启用查询日志记录。

django.utils.autoreload

与 Django 开发服务器执行期间自动代码重新加载相关的日志消息。此记录器在检测到源代码文件的修改时生成 INFO 消息,并在文件系统检查和事件订阅过程中可能生成 WARNING 消息。

django.contrib.auth

New in Django 4.2.16.

Log messages related to django.contrib.auth, particularly ERROR messages are generated when a PasswordResetForm is successfully submitted but the password reset email cannot be delivered due to a mail sending exception.

django.contrib.gis

GeoDjango 相关的日志消息在各个时刻:在加载外部地理空间库(GEOS、GDAL 等)和报告错误时。每个 ERROR 日志记录都包括捕获的异常和相关的上下文数据。

django.dispatch

这个记录器在 信号 中使用,特别是在 Signal 类中,用于在将信号分派给连接的接收器时报告问题。ERROR 日志记录包括捕获的异常作为 exc_info 并添加以下额外的上下文:

  • receiver:接收器的名称。

  • err:调用接收器时发生的异常。

django.security.*

安全记录器将接收任何发生 SuspiciousOperation 和其他安全相关错误的消息。每个子类型的安全错误都有一个子记录器,包括所有 SuspiciousOperations。日志事件的级别取决于异常处理的位置。 大多数发生的事件被记录为警告,而任何到达 WSGI 处理程序的 SuspiciousOperation 将被记录为错误。例如,当客户端的请求中包含一个 HTTP Host 头,而这个头不符合 ALLOWED_HOSTS 时,Django 会返回一个 400 的响应,并且错误信息会被记录到 django.security.DisallowedHost 记录器中。

这些日志事件默认会到达 django 日志器,当 DEBUG=False 时,记录器会将错误事件发送给管理员。由于 SuspiciousOperation 导致 400 响应的请求不会被记录到 django.request 记录器,而只会记录到 django.security 记录器。

要使某一特定类型的 SuspiciousOperation 保持沉默,你可以按照以下示例覆盖该特定的记录器:

LOGGING = {
    # ...
    "handlers": {
        "null": {
            "class": "logging.NullHandler",
        },
    },
    "loggers": {
        "django.security.DisallowedHost": {
            "handlers": ["null"],
            "propagate": False,
        },
    },
    # ...
}

其他不基于 SuspiciousOperationdjango.security 记录器是:

django.db.backends.schema

记录 migrations framework 对数据库进行模式变更时执行的 SQL 查询。请注意,它不会记录 RunPython 执行的查询。给这个记录器的消息在其额外的上下文中有 paramssql (但与 django.db.backends 不同,不是 duration)。这些值的含义与 django.db.backends 中的解释相同。

django.contrib.sessions

Log messages related to the session framework.

Handlers

除了 Python 日志模块提供的处理程序外,Django 还提供了一个日志处理程序。

class AdminEmailHandler(include_html=False, email_backend=None, reporter_class=None)[source]

该处理程序对收到的每条日志消息都会向站点 ADMINS 发送一封邮件。

如果日志记录中包含 request 属性,电子邮件中会包含请求的全部细节。如果客户的 IP 地址在 INTERNAL_IPS 设置中,电子邮件主题将包括“内部 IP”;如果没有,则包括“外部 IP”。

如果日志记录中包含堆栈跟踪信息,该堆栈跟踪信息将包含在电子邮件中。

AdminEmailHandlerinclude_html 参数用于控制是否在 traceback 邮件中包含一个 HTML 附件,该附件包含了如果 DEBUGTrue 时会生成的完整调试网页的内容。要在配置中设置此值,将其包含在 django.utils.log.AdminEmailHandler 的处理程序定义中,如下所示:

"handlers": {
    "mail_admins": {
        "level": "ERROR",
        "class": "django.utils.log.AdminEmailHandler",
        "include_html": True,
    },
}

在使用 AdminEmailHandler 时要注意 日志记录的安全性影响

通过设置 AdminEmailHandleremail_backend 参数,处理程序使用的 email 后端 可以被覆盖,就像这样:

"handlers": {
    "mail_admins": {
        "level": "ERROR",
        "class": "django.utils.log.AdminEmailHandler",
        "email_backend": "django.core.mail.backends.filebased.EmailBackend",
    },
}

默认情况下,将使用 EMAIL_BACKEND 中指定的电子邮件后端实例。

AdminEmailHandlerreporter_class 参数允许提供一个 django.view.debug.ExceptionReporter 子类来自定义邮件正文中发送的回溯文本。你提供一个字符串的导入路径到你想使用的类,像这样:

"handlers": {
    "mail_admins": {
        "level": "ERROR",
        "class": "django.utils.log.AdminEmailHandler",
        "include_html": True,
        "reporter_class": "somepackage.error_reporter.CustomErrorReporter",
    },
}
send_mail(subject, message, *args, **kwargs)[source]

向管理员用户发送邮件。要自定义这个行为,你可以将 AdminEmailHandler 类子类化,并覆盖这个方法。

过滤器

除了 Python 日志模块提供的日志过滤器外,Django 还提供了一些日志过滤器。

class CallbackFilter(callback)[source]

这个过滤器接受一个回调函数(它应该接受一个单一的参数,即要记录的记录),并对每个通过过滤器的记录进行调用。如果回调函数返回 False,则不会对该记录进行处理。

例如,要从管理员邮件中过滤掉 UnreadablePostError (当用户取消上传时引发),你可以创建一个过滤函数:

from django.http import UnreadablePostError


def skip_unreadable_post(record):
    if record.exc_info:
        exc_type, exc_value = record.exc_info[:2]
        if isinstance(exc_value, UnreadablePostError):
            return False
    return True

然后将其添加到你的日志记录配置中:

LOGGING = {
    # ...
    "filters": {
        "skip_unreadable_posts": {
            "()": "django.utils.log.CallbackFilter",
            "callback": skip_unreadable_post,
        },
    },
    "handlers": {
        "mail_admins": {
            "level": "ERROR",
            "filters": ["skip_unreadable_posts"],
            "class": "django.utils.log.AdminEmailHandler",
        },
    },
    # ...
}
class RequireDebugFalse[source]

只有当 settings.DEBUG 为 False 时,该过滤器才会传递记录。

该过滤器在默认的 logging 配置中使用如下,以确保 AdminEmailHandler 只在 DEBUGFalse 时向管理员发送错误邮件:

LOGGING = {
    # ...
    "filters": {
        "require_debug_false": {
            "()": "django.utils.log.RequireDebugFalse",
        },
    },
    "handlers": {
        "mail_admins": {
            "level": "ERROR",
            "filters": ["require_debug_false"],
            "class": "django.utils.log.AdminEmailHandler",
        },
    },
    # ...
}
class RequireDebugTrue[source]

该过滤器类似于 RequireDebugFalse,但只有当 DEBUGTrue 时才会传递记录。

Back to Top