43👍
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)
6👍
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.
- [Django]-Django – what is the difference between render(), render_to_response() and direct_to_template()?
- [Django]-Django TemplateDoesNotExist?
- [Django]-Django 3.1 | Admin page appearance issue
5👍
Yes you can manually send email error report even if you catch the exception.
There are several ways you can go about this.
- You can use the existing default logger configuration (and its associated handler configuration, documented 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.
- You can add additional logger configuration which uses the same handler, to catch your exception earlier than django.request and call log.error earlier.
- You can subclass django.request, specifically handle_uncaught_exception.
- You can use a custom middleware ( for example StandardExceptionMiddleware) or ExceptionMiddleware
- You can manually call the contents of emit in
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,
},
- [Django]-How can I disable Django's csrf protection only in certain cases?
- [Django]-"{% extends %}" vs "{% include %}" in Django Templates
- [Django]-Django 1.7 upgrade error: AppRegistryNotReady: Apps aren't loaded yet
5👍
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?
- [Django]-Testing email sending in Django
- [Django]-Django: OperationalError No Such Table
- [Django]-Simply save file to folder in Django
0👍
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()
)
- [Django]-Model name of objects in django templates
- [Django]-Django Form File Field disappears on form error
- [Django]-Inline Form Validation in Django
0👍
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(),
)
- [Django]-How to add annotate data in django-rest-framework queryset responses?
- [Django]-Django check if object in ManyToMany field
- [Django]-Catching DoesNotExist exception in a custom manager in Django