Reputation: 12903
Django error reporting handles uncaught exceptions by sending an email, and (optionally) shows user a nice 500 error page.
This works very well, but in a few instances I'd like to allow users to continue with their business uninterrupted, but still have Django send me the email error report about the exception.
So basically: can I manually send email error report even if I catch the exception?
Of course, I'd like to avoid manually generating the error report email.
Upvotes: 36
Views: 6870
Reputation: 1719
Here is a trimmed down version of @gitaarik's solution, adapted to 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(),
)
Upvotes: 0
Reputation: 46410
Building on @JuniorCompressor's answer, this is the code that I use:
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()
)
Upvotes: 0
Reputation: 29594
Just setup a simple log handler in your settings.
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,
},
}
}
and then in your view, you can do anything
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
If you want detailed error report, you can try something like this.
You also need to take care of sensitive information.
Upvotes: 7
Reputation: 5241
I mostly use this pattern with the standard error reporting.
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
It will trigger the built in error reporting and logger.exception will catch the stack frame. https://docs.djangoproject.com/en/1.8/topics/logging/#making-logging-calls
edit:
I noticed some information was missing in the email and to get an exact traceback as the built in the following can be used instead:
logger.exception('Internal Server Error: %s', request.path,
extra={'status_code': 500, 'request': request})
More info found here: How to send django exception log manually?
Upvotes: 5
Reputation: 20025
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)
Upvotes: 42
Reputation: 16116
Yes you can manually send email error report even if you catch the exception.
There are several ways you can go about this.
AdminEmailHandler
or mail.mail_admins directly.Of these options, Option 4 seems to be the most commonly done.
Based on the additional information in your comment a code example of 2 is below.
First the code that would be added to view
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>')
This is based of Django documentation for view writing and and introduction to Django logging, but hasn't been tested.
Then the additional logger configuration is add to the to the loggers entry (as per here)
'nameofdjangoapplicationgoeshere': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
Upvotes: 5