Error reporting

当你运行一个公开站点时,你应该始终关闭DEBUG 设置。 这会使你的服务器运行得更快,也会防止恶意用户看到由错误页面展示的一些应用细节。

但是,运行在 DEBUGFalse的情况下,你不会看到你的站点所生成的错误 -- 每个人都只能看到公开的错误页面。 你需要跟踪部署的站点上的错误,所以可以配置Django来生成带有错误细节的报告。

电子邮件报告

服务器错误

DEBUGFalse的时候,无论什么时候代码产生了未处理的异常,并且出现了服务器内部错误(HTTP状态码 500),Django 都会给ADMINS设置中的用户发送邮件。 这会向管理员提供任何错误的及时通知。 ADMINS会得到一份错误的描述,完整的Python traceback,以及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错误的邮件:

如果符合这些条件,无论什么时候你的代码产生404错误,并且请求带有referer, Django 都会给MANAGERS中的用户发送邮件。 电子邮件没有打扰给没有引用者的404s - 通常只是人们在破碎的网址或破碎的Web机器人中输入内容。 当引用者等于所请求的URL时,它也忽略404,因为这种行为也是来自破碎的Web机器人。

BrokenLinkEmailsMiddleware 必须出现在其它拦截404错误的中间件之前,比如 LocaleMiddleware 或者 FlatpageFallbackMiddleware 将其放置在MIDDLEWARE设置的顶部。

你可以通过调整IGNORABLE_404_URLS设置,告诉Django停止报告特定的404错误。 它应该是编译的正则表达式对象的列表。 像这样:

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

在这个例子中,任何以.php 或者.cgi结尾URL的404错误都不会报告。 任何以/phpmyadmin/开头的URL也不会。

下面的例子展示了如何排除一些浏览器或爬虫经常请求的常用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,将它们用于错误报告。

过滤错误报告

警告

过滤敏感数据是一个困难的问题,几乎不可能保证敏感数据不会泄漏到错误报告中。 因此,错误报告只能由可信任的小组成员使用,您应避免在互联网上传递未加密的错误报告(例如通过电子邮件)。

过滤敏感信息

错误报告对错误的调试真的很有用,所以对于这些错误,通常它会尽可能多的记录下相关信息。 例如,通常DJango会为产生的异常记录完整的tracebacktraceback 帧的每个局部变量,以及HttpRequestattributes

然而,有时特定的消息类型十分敏感,并不适合跟踪消息,比如用户的密码或者信用卡卡号。 因此,除了过滤掉DEBUG文档中描述的敏感的设置外,Django还提供了一组功能装饰器,可帮助您控制哪些信息应从生产环境中的错误报告中过滤掉(也就是说,DEBUG设置为False):sensitive_variables()sensitive_post_parameters()

sensitive_variables(*variables)[source]

如果你的代码中一个函数(视图或者常规的回调)使用可能含有敏感信息的局部变量,你可能需要使用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
    ...

在上面的例子中,name, userpw 变量的值会在错误报告中隐藏并且使用星号(**********) 来代替,虽然cc 变量的值会公开。

要想有顺序地在错误报告中隐藏一个函数的所有局部变量,不要向sensitive_variables 装饰器提供任何参数:

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

使用多个装饰器的时候

如果你想要隐藏的变量也是一个函数的参数(例如,下面例子中的user),并且被装饰的函数有多个装饰器,你需要确保将@sensitive_variables 放在装饰器链的顶端。 这种方法也会隐藏函数参数,尽管它通过其它装饰器传递:

@sensitive_variables('user', 'pw', 'cc')
@some_decorator
@another_decorator
def process_info(user):
    ...
sensitive_post_parameters(*parameters)[source]

如果你的代码中一个视图接收到了可能带有敏感信息的,带有POST parametersHttpRequest对象,你可能需要使用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'],
    )
    ...

在上面的例子中,namepass_word POST参数的值会在错误报告中隐藏并且使用星号(**********) 来代替,虽然credit_card_number变量的值会公开。

要想有顺序地在错误报告中隐藏一个请求的所有POST 参数,不要向sensitive_post_parameters 装饰器提供任何参数:

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

所有POST参数按顺序被过滤出特定django.contrib.auth.views 视图的错误报告(password_change, password_reset_confirm, user_change_password, loginauth中的add_view),来防止像是用户密码这样的敏感信息的泄露。

自定义错误报告

所有sensitive_variables()sensitive_post_parameters()分别用敏感变量的名字向被装饰的函数添加注解,以及用POST敏感参数的名字向HttpRequest对象添加注解,以便在错误产生时可以随后过滤掉报告中的敏感信息。 Django的默认错误报告过滤器django.views.debug.SafeExceptionReporterFilter会完成实际的过滤操作。 产生错误报告的时候,这个过滤器使用装饰器的注解来将相应的值替换为星号 (**********) 。 如果你希望为你的整个站点覆写或自定义这一默认的属性,你需要定义你自己的过滤器类,并且通过DEFAULT_EXCEPTION_REPORTER_FILTER 设置来让Django使用它。

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,并且可能需要覆写以下方法:

SafeExceptionReporterFilter[source]
SafeExceptionReporterFilter。is_active(request)[source]

如果其它方法中操作的过滤器已激活,返回True 如果 DEBUGFalse,通常过滤器是激活的。

SafeExceptionReporterFilter。get_post_parameters(request)[source]

返回过滤后的POST参数字典。 通常它会把敏感参数的值以星号 (**********)替换。

SafeExceptionReporterFilter。get_traceback_frame_variables请求tb_frame[source]

返回过滤后的,所提供traceback帧的局部变量的字典。 通常它会把敏感变量的值以星号 (**********)替换。

请参见

你也可以通过编写自定义的exception middleware来建立自定义的错误报告。 如果你编写了自定义的错误处理器,模拟Django内建的错误处理器,只在DEBUGFalse时报告或记录错误是个好主意。