如何管理错误报告

当你运行一个公共站点时,你应该总是关闭 DEBUG 设置。这将使您的服务器运行得更快,并且还将防止恶意用户看到错误页面可以显示的应用程序的详细信息。

但是,使用 DEBUG 设置为 False 这意味着你永远不会看到你的网站产生的错误——每个人都会看到你的公共错误页面。您需要跟踪部署站点中发生的错误,因此可以将Django配置为创建包含这些错误的详细信息的报告。

电子邮件报告

服务器错误

什么时候? DEBUGFalse ,Django将通过电子邮件向 ADMINS 每当代码引发未经处理的异常并导致内部服务器错误时设置(严格来说,对于HTTP状态代码为500或更高的任何响应)。立即通知管理员此错误。这个 ADMINS 将获取错误的描述、完整的python回溯以及导致错误的HTTP请求的详细信息。

备注

为了发送电子邮件,Django需要一些设置来告诉它如何连接到邮件服务器。至少,您需要指定 EMAIL_HOST 而且可能 EMAIL_HOST_USEREMAIL_HOST_PASSWORD 尽管根据邮件服务器的配置,可能还需要其他设置。查阅 the Django settings documentation 有关电子邮件相关设置的完整列表。

默认情况下,django将从root@localhost发送电子邮件。但是,有些邮件提供商拒绝来自此地址的所有电子邮件。若要使用其他发件人地址,请修改 SERVER_EMAIL 设置。

若要激活此行为,请将收件人的电子邮件地址 ADMINS 设置。

参见

服务器错误电子邮件是使用日志框架发送的,因此您可以通过以下方式自定义此行为: customizing your logging configuration .

404误差

Django还可以配置为通过电子邮件发送有关断开链接的错误(404“找不到页面”错误)。当出现以下情况时,Django会发送大约404个错误的电子邮件:

如果满足这些条件,Django将向 MANAGERS 只要您的代码引发404,并且请求具有引用,就会设置。对于没有推荐人的404,不用费心发电子邮件--这些人通常是输入损坏的URL或损坏的网络机器人。当Referer等于请求的URL时,它也会忽略404,因为这一行为也来自损坏的网络机器人。

备注

BrokenLinkEmailsMiddleware 必须出现在拦截404错误的其他中间件之前,例如 LocaleMiddlewareFlatpageFallbackMiddleware 。把它放在你的头顶 MIDDLEWARE 布景。

您可以通过调整 IGNORABLE_404_URLS 设置。它应该是已编译正则表达式对象的列表。例如::

import re

IGNORABLE_404_URLS = [
    re.compile(r"\.(php|cgi)$"),
    re.compile(r"^/phpmyadmin/"),
]

在本例中,404指向以 .php.cginot 被报道。任何URL都不会以 /phpmyadmin/ .

下面的示例显示如何排除浏览器和爬虫程序经常请求的一些常规URL::

import re

IGNORABLE_404_URLS = [
    re.compile(r"^/apple-touch-icon.*\.png$"),
    re.compile(r"^/favicon\.ico$"),
    re.compile(r"^/robots\.txt$"),
]

(请注意,这些是正则表达式,因此我们在句点前面加上一个反斜杠以转义它们。)

如果您想自定义 django.middleware.common.BrokenLinkEmailsMiddleware 此外(例如,要忽略来自Web爬虫的请求),您应该将其子类化并重写其方法。

参见

使用日志框架记录404个错误。默认情况下,这些日志记录将被忽略,但您可以通过编写处理程序和 configuring logging 适当地。

筛选错误报告

警告

过滤敏感数据是一个困难的问题,几乎不可能保证敏感数据不会泄露到错误报告中。因此,错误报告应该只对受信任的团队成员可用,并且您应该避免通过Internet(如通过电子邮件)传输未加密的错误报告。

过滤敏感信息

错误报告确实有助于调试错误,因此尽可能多地记录这些错误的相关信息通常很有用。例如,默认情况下,Django记录 full traceback 对于引发的异常,每个 traceback frame 的局部变量,以及 HttpRequestattributes .

但是,有时某些类型的信息可能过于敏感,因此可能不适合跟踪,例如用户的密码或信用卡号。因此,除了筛选出看起来很敏感的设置外,如中所述 DEBUG 文档,Django提供了一组函数修饰器来帮助您控制在生产环境(即 DEBUG 设置为 False ): sensitive_variables()sensitive_post_parameters() .

sensitive_variables(*variables)[源代码]

如果代码中的函数(视图或任何常规回调)使用易受敏感信息影响的局部变量,则可以使用 sensitive_variables 装饰师:

from django.views.decorators.debug import sensitive_variables


@sensitive_variables("user", "pw", "cc")
def process_info(user):
    pw = user.pass_word
    cc = user.credit_card_number
    name = user.name
    ...

在上面的示例中, userpwcc 变量将被隐藏并替换为星型 (********** )在错误报告中,而 name 变量将被披露。

要系统地从错误日志中隐藏函数的所有局部变量,请不要向 sensitive_variables 装饰师:

@sensitive_variables()
def my_function():
    ...

使用多个修饰符时

如果要隐藏的变量也是一个函数参数(例如下面的示例中的“user``”),并且修饰函数有多个修饰符,请确保 @sensitive_variables 在装饰链的顶部。这样,它还将在传递给其他修饰符时隐藏函数参数:

@sensitive_variables("user", "pw", "cc")
@some_decorator
@another_decorator
def process_info(user):
    ...
Changed in Django 5.0:

支持包装 async 添加了函数。

sensitive_post_parameters(*parameters)[源代码]

如果你的一个观点 HttpRequest 对象与 POST parameters 易受包含敏感信息的影响,您可以使用 sensitive_post_parameters 装饰师:

from django.views.decorators.debug import sensitive_post_parameters


@sensitive_post_parameters("pass_word", "credit_card_number")
def record_user_profile(request):
    UserProfile.create(
        user=request.user,
        password=request.POST["pass_word"],
        credit_card=request.POST["credit_card_number"],
        name=request.POST["name"],
    )
    ...

在上面的示例中, pass_wordcredit_card_number post参数将被隐藏并替换为星型 (********** )在错误报告中请求的表示形式中,而 name 将公开参数。

要在错误报告中系统地隐藏请求的所有post参数,请不要向 sensitive_post_parameters 装饰师:

@sensitive_post_parameters()
def my_view(request):
    ...

系统地从错误报告中筛选出所有post参数 django.contrib.auth.views 意见 (loginpassword_reset_confirmpassword_changeadd_viewuser_change_passwordauth admin)防止敏感信息(如用户密码)泄漏。

Changed in Django 5.0:

支持包装 async 添加了函数。

自定义错误报告

所有 sensitive_variables()sensitive_post_parameters() do分别用敏感变量的名称注释修饰函数,并注释 HttpRequest 具有敏感的post参数名称的对象,以便在发生错误时从报告中筛选出这些敏感信息。实际过滤由Django的默认错误报告程序过滤器完成: django.views.debug.SafeExceptionReporterFilter . 此筛选器使用装饰器的注释用星替换相应的值 (********** )生成错误报告时。如果要覆盖或自定义整个网站的默认行为,则需要定义自己的筛选器类,并告诉Django通过 DEFAULT_EXCEPTION_REPORTER_FILTER 设置:

DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"

您还可以通过设置 HttpRequestexception_reporter_filter 属性:

def my_view(request):
    if request.user.is_authenticated:
        request.exception_reporter_filter = CustomExceptionReporterFilter()
    ...

自定义筛选器类需要从继承 django.views.debug.SafeExceptionReporterFilter 并且可以重写以下属性和方法:

class SafeExceptionReporterFilter[源代码]
cleansed_substitute

要替换敏感值的字符串值。默认情况下,它用星星代替敏感变量的值 (**********

hidden_settings

用于匹配设置和的已编译正则表达式对象 request.META 敏感值。默认情况下等效于:

import re

re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
is_active(request)[源代码]

返回 True 在中激活过滤 get_post_parameters()get_traceback_frame_variables() . 默认情况下,如果 DEBUGFalse . 注意敏感 request.META 值始终与敏感设置值一起过滤,如中所述 DEBUG 文档。

get_post_parameters(request)[源代码]

返回已筛选的POST参数字典。敏感值替换为 cleansed_substitute .

get_traceback_frame_variables(request, tb_frame)[源代码]

返回给定回溯帧的已筛选局部变量字典。敏感值替换为 cleansed_substitute .

如果需要自定义过滤之外的错误报告,可以通过定义 DEFAULT_EXCEPTION_REPORTER 设置:

DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"

异常报告器负责编译异常报告数据,并将其适当地格式化为文本或HTML。(例外报告者使用 DEFAULT_EXCEPTION_REPORTER_FILTER 准备异常报告数据时。)

您的自定义报告器类需要继承自 django.views.debug.ExceptionReporter .

class ExceptionReporter[源代码]
html_template_path

属性返回一个 pathlib.Path 表示用于呈现异常的HTML表示形式的模板的绝对文件系统路径。默认为Django提供的模板。

text_template_path

属性返回一个 pathlib.Path 表示用于呈现异常的纯文本表示形式的模板的绝对文件系统路径。默认为Django提供的模板。

get_traceback_data()[源代码]

返回包含回溯信息的字典。

这是自定义异常报告的主要扩展点,例如:

from django.views.debug import ExceptionReporter


class CustomExceptionReporter(ExceptionReporter):
    def get_traceback_data(self):
        data = super().get_traceback_data()
        # ... remove/add something here ...
        return data
get_traceback_html()[源代码]

返回异常报告的HTML版本。

用于调试500 HTTP错误页的HTML版本。

get_traceback_text()[源代码]

返回异常报告的纯文本版本。

用于debug 500 HTTP错误页和电子邮件报告的纯文本版本。

与filter类一样,您可以通过设置 HttpRequestexception_reporter_class 属性:

def my_view(request):
    if request.user.is_authenticated:
        request.exception_reporter_class = CustomExceptionReporter()
    ...

参见

还可以通过编写自定义错误报告 exception middleware . 如果您确实编写自定义错误处理,那么最好模拟Django的内置错误处理,并且仅在以下情况下报告/记录错误: DEBUGFalse .