35

Django 错误报告通过发送电子邮件来处理未捕获的异常,并且(可选地)向用户显示一个漂亮的 500 错误页面。

这非常有效,但在某些情况下,我希望允许用户不间断地继续他们的业务,但仍然让 Django 向我发送有关异常的电子邮件错误报告。

所以基本上:即使我发现异常,我也可以手动发送电子邮件错误报告吗?

当然,我想避免手动生成错误报告电子邮件。

4

6 回答 6

41

You can use the following code to send manually an email about a request and an exception e:

import sys
import traceback
from django.core import mail
from django.views.debug import ExceptionReporter

def send_manually_exception_email(request, e):
    exc_info = sys.exc_info()
    reporter = ExceptionReporter(request, is_email=True, *exc_info)
    subject = e.message.replace('\n', '\\n').replace('\r', '\\r')[:989]
    message = "%s\n\n%s" % (
        '\n'.join(traceback.format_exception(*exc_info)),
        reporter.filter.get_request_repr(request)
    )
    mail.mail_admins(
        subject, message, fail_silently=True,
        html_message=reporter.get_traceback_html()
    )

You can test it in a view like this:

def test_view(request):
    try:
        raise Exception
    except Exception as e:
        send_manually_exception_email(request, e)
于 2015-04-26T13:54:50.903 回答
6

只需在您的设置中设置一个简单的日志处理程序。

LOGGING = {
    'version': 1, 
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },
        'app': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

然后在你看来,你可以做任何事

 import logging
 logger = logging.getLogger('app')

 def some_view(request):
     try:
         # something
         if something_wnet_wrong:
             logger.error('Something went wrong!')
         return some_http_response
     except:
         #something else
         logger.error(sys.exc_info(), request)        
         return some_other_response

如果你想要详细的错误报告,你可以尝试这样的事情

您还需要处理敏感信息

于 2015-04-23T09:42:51.023 回答
5

是的,即使您发现异常,您也可以手动发送电子邮件错误报告。

有几种方法可以解决这个问题。

  1. 您可以为 django.request 使用现有的默认记录器配置(及其相关的处理程序配置,记录在此处),它将所有错误消息发送到 mail_admins 处理程序,当 debug 为 false 时,该处理程序会从 django.request 发送使用 log.error 记录的任何内容使用AdminEmailHandler的电子邮件,其现有调用点位于handle_uncaught_exception中。
  2. 您可以添加使用相同处理程序的其他记录器配置,以便比 django.request 更早地捕获您的异常并更早地调用 log.error。
  3. 你可以继承 django.request,特别是 handle_uncaught_exception。
  4. 您可以使用自定义中间件(例如 StandardExceptionMiddleware)或ExceptionMiddleware
  5. 您可以直接手动调用emit inAdminEmailHandler或mail.mail_admins 的内容。

在这些选项中,选项 4 似乎是最常用的。

根据您评论中的附加信息,下面是 2 的代码示例。

首先是要添加到视图的代码

from django.http import HttpResponse
import logging
logger = logging.getLogger(__name__)

def my_view(request):

    try:
        result = do_something()
        return HttpResponse('<h1>Page was found' + result + '</h1>')
    except Exception: 
         # Can have whatever status_code and title you like, but I was just matching the existing call.
         logger.error('Internal Server Error: %s', request.path,
            exc_info=sys.exc_info(),
            extra={
            'status_code': 500,
            'request': request
            }
         )
         return HttpResponse('<h1>Page was found, and exception was mailed to admins.</h1>')

这是基于Django 文档,用于编写视图介绍 Django 日志记录,但尚未经过测试。

然后将额外的记录器配置添加到记录器条目中(根据此处

'nameofdjangoapplicationgoeshere': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
于 2015-04-23T04:12:32.650 回答
4

我主要将此模式与标准错误报告一起使用。

import logging    
logger = logging.getLogger('django.request')

#code block in view
try:
    #code that can raise exception
except:
    logger.exception('Information')
#continue as nothing happend

它将触发内置的错误报告,并且 logger.exception 将捕获堆栈帧。https://docs.djangoproject.com/en/1.8/topics/logging/#making-logging-calls

编辑:

我注意到电子邮件中缺少一些信息并获得准确的回溯,因为可以使用以下内置内容:

logger.exception('Internal Server Error: %s', request.path,
                 extra={'status_code': 500, 'request': request})

在这里找到更多信息: 如何手动发送 django 异常日志?

于 2015-04-29T22:14:39.693 回答
0

基于@JuniorCompressor 的回答,这是我使用的代码:

import sys
from django.core import mail
from django.views.debug import ExceptionReporter

def send_exception_email(request, exception, subject_prefix=''):

    exc_info = sys.exc_info()
    reporter = ExceptionReporter(request, *exc_info, is_email=True)

    def exception_name():
        if exc_info[0]:
            return exc_info[0].__name__
        return 'Exception'

    def subject_suffix():
        if request:
            return '{} at {}'.format(
                exception_name(),
                request.path_info
            )
        return exception_name()

    def subject():
        return '{}{}'.format(
            subject_prefix,
            subject_suffix()
        )

    mail.mail_admins(
        subject=subject(),
        message=reporter.get_traceback_text(),
        fail_silently=True,
        html_message=reporter.get_traceback_html()
    )
于 2018-12-04T12:40:12.073 回答
0

这是@gitaarik 解决方案的精简版,适用于 Python 3:

import sys

from django.core import mail
from django.views.debug import ExceptionReporter

def send_exception_email(request, exception, subject_prefix=''):
    exc_info = sys.exc_info()

    exception_name = exc_info[0].__name__ if exc_info[0] else 'Exception'
    request_path = f" at {request.path_info}" if request else ''

    reporter = ExceptionReporter(request, *exc_info, is_email=True)

    mail.mail_admins(
        subject=f"{subject_prefix}{exception_name}{request_path}",
        message=reporter.get_traceback_text(),
        fail_silently=True,
        html_message=reporter.get_traceback_html(),
    )
于 2020-12-15T15:20:33.630 回答