手动触发Django邮件报错
Manually trigger Django email error report
Django error reporting 通过发送电子邮件处理未捕获的异常,并(可选)向用户显示一个漂亮的 500 错误页面。
这非常有效,但在某些情况下,我希望允许用户不间断地继续他们的业务,但仍然让 Django 向我发送有关异常的电子邮件错误报告。
所以基本上:我可以手动发送电子邮件错误报告,即使我捕获了异常吗?
当然,我想避免手动生成错误报告电子邮件。
是的,即使您捕获到异常,您也可以手动发送电子邮件错误报告。
您可以通过多种方式解决此问题。
- 您可以使用现有的默认记录器配置(及其关联的处理程序配置,已记录 here) for django.request which sends all error messages to the mail_admins handler, which sends the anything logged with log.error from django.request when debug is false as email using AdminEmailHandler, whose existing call point is in handle_uncaught_exception。
- 您可以添加使用相同处理程序的额外记录器配置,以便比 django.request 更早捕获异常并更早调用 log.error。
- 您可以继承 django.request,特别是 handle_uncaught_exception。
- 您可以使用自定义中间件 (for example StandardExceptionMiddleware) or ExceptionMiddleware
- 可以直接手动调用
AdminEmailHandler
或mail.mail_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>')
这是基于 Django documentation for view writing and and introduction to Django logging,但尚未经过测试。
然后将额外的记录器配置添加到记录器条目中(根据 here)
'nameofdjangoapplicationgoeshere': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
只需在您的设置中设置一个简单的日志处理程序。
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
如果你想要详细的错误报告,你可以尝试something like this。
您还需要照顾sensitive information。
您可以使用以下代码手动发送有关 request
和异常 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 将捕获堆栈帧。 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})
在此处找到更多信息:
How to send django exception log manually?
基于@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:
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(),
)
Django error reporting 通过发送电子邮件处理未捕获的异常,并(可选)向用户显示一个漂亮的 500 错误页面。
这非常有效,但在某些情况下,我希望允许用户不间断地继续他们的业务,但仍然让 Django 向我发送有关异常的电子邮件错误报告。
所以基本上:我可以手动发送电子邮件错误报告,即使我捕获了异常吗?
当然,我想避免手动生成错误报告电子邮件。
是的,即使您捕获到异常,您也可以手动发送电子邮件错误报告。
您可以通过多种方式解决此问题。
- 您可以使用现有的默认记录器配置(及其关联的处理程序配置,已记录 here) for django.request which sends all error messages to the mail_admins handler, which sends the anything logged with log.error from django.request when debug is false as email using AdminEmailHandler, whose existing call point is in handle_uncaught_exception。
- 您可以添加使用相同处理程序的额外记录器配置,以便比 django.request 更早捕获异常并更早调用 log.error。
- 您可以继承 django.request,特别是 handle_uncaught_exception。
- 您可以使用自定义中间件 (for example StandardExceptionMiddleware) or ExceptionMiddleware
- 可以直接手动调用
AdminEmailHandler
或mail.mail_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>')
这是基于 Django documentation for view writing and and introduction to Django logging,但尚未经过测试。
然后将额外的记录器配置添加到记录器条目中(根据 here)
'nameofdjangoapplicationgoeshere': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
只需在您的设置中设置一个简单的日志处理程序。
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
如果你想要详细的错误报告,你可以尝试something like this。
您还需要照顾sensitive information。
您可以使用以下代码手动发送有关 request
和异常 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 将捕获堆栈帧。 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})
在此处找到更多信息: How to send django exception log manually?
基于@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:
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(),
)