Python 手动触发Django电子邮件错误报告

Python 手动触发Django电子邮件错误报告,python,django,exception-handling,django-email,django-errors,Python,Django,Exception Handling,Django Email,Django Errors,通过发送电子邮件处理未捕获的异常,并且(可选)向用户显示一个漂亮的500错误页面 这工作得很好,但在一些情况下,我希望允许用户不间断地继续他们的业务,但仍然让Django向我发送有关异常的电子邮件错误报告 因此,基本上:我可以手动发送电子邮件错误报告,即使我捕捉到异常 当然,我希望避免手动生成错误报告电子邮件。是的,即使捕捉到异常,您也可以手动发送电子邮件错误报告 有几种方法可以做到这一点 您可以对django.request使用现有的默认记录器配置(及其相关的处理程序配置,有文档记录),该配置

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

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

因此,基本上:我可以手动发送电子邮件错误报告,即使我捕捉到异常


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

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

有几种方法可以做到这一点

  • 您可以对django.request使用现有的默认记录器配置(及其相关的处理程序配置,有文档记录),该配置将所有错误消息发送给mail_admins处理程序,当调试为false时,该处理程序将使用django.request中的log.error记录的任何内容发送给email using,其现有调用点位于
  • 您可以添加使用相同处理程序的其他记录器配置,以便在django.request之前捕获异常,并更早调用log.error
  • 您可以将django.request子类化,专门处理_uncaught_异常
  • 您可以使用自定义中间件()或
  • 您可以在
    AdminEmailHandler
    或mail.mail\u admins中手动调用emit的内容
  • 在这些选项中,选项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>')
    

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

    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
    
    如果需要详细的错误报告,可以尝试


    您还需要注意。

    您可以使用以下代码手动发送有关
    请求
    和异常
    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()
        )
    
    您可以在如下视图中对其进行测试:

    def test_view(request):
        try:
            raise Exception
        except Exception as e:
            send_manually_exception_email(request, e)
    

    我主要在标准错误报告中使用这种模式

    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将捕获堆栈帧

    编辑:

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

    logger.exception('Internal Server Error: %s', request.path,
                     extra={'status_code': 500, 'request': request})
    
    更多信息可在此处找到:

    基于@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()
        )
    

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

    导入系统 从django.core导入邮件 从django.views.debug导入异常报告程序 def发送异常电子邮件(请求、异常、主题前缀=“”): exc_info=sys.exc_info() 异常\u名称=exc\u信息[0]。\u名称\u如果exc\u信息[0]为其他“异常” 请求路径=f“在{request.path\u info}”处,如果请求其他“” 报告者=例外报告者(请求,*exc\u信息,is\u email=True) mail.mail\u管理员( subject=f“{subject\u prefix}{exception\u name}{request\u path}”, message=reporter.get_traceback_text(), 失败=正确, html\u message=reporter.get\u traceback\u html(), )
    我希望从视图触发错误报告,然后像往常一样继续操作(即允许视图返回HttpResponse),因此我认为中间件不会这样做。还是我错过了smth,@Brandon的评论也表明了这一点?选项1和2似乎是答案。想添加一个代码示例吗?太好了!尽管没有一个答案能够准确地生成自动生成的错误报告,但这种方法提供了大部分信息。这类似于Django显示的错误页面,其中包含
    DEBUG=True
    我在第9行中遇到了一个错误。它说:
    'Exception'对象没有属性'message'
    这也会像电子邮件报告一样过滤敏感数据,除非默认的\u Exception\u REPORTER\u过滤器设置为不包含该属性的过滤器。(至少在Django 1.9.6上)
    get_request_repr
    已在Django 1.10中删除。我现在使用的是
    message=reporter.get\u traceback\u text
    ,这与Django发送的自动电子邮件相比,更像是
    debug=True
    错误页面。
    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()
        )