Fixes #2266: Permit additional logging of exceptions beyond custom middleware

This commit is contained in:
Jeremy Stretch 2018-07-23 23:00:09 -04:00
parent b518258e6d
commit c8a73b5b15
3 changed files with 40 additions and 15 deletions

View File

@ -74,3 +74,5 @@ if settings.DEBUG:
urlpatterns = [
url(r'^{}'.format(settings.BASE_PATH), include(_patterns))
]
handler500 = 'utilities.views.server_error'

View File

@ -4,8 +4,8 @@ import sys
from django.conf import settings
from django.db import ProgrammingError
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render
from django.http import Http404, HttpResponseRedirect, HttpResponseServerError
from django.template import loader
from django.urls import reverse
BASE_PATH = getattr(settings, 'BASE_PATH', False)
@ -65,23 +65,24 @@ class ExceptionHandlingMiddleware(object):
if isinstance(exception, Http404):
return
# Determine the type of exception
# Determine the type of exception. If it's a common issue, return a custom error page with instructions.
custom_template = None
if isinstance(exception, ProgrammingError):
template_name = 'exceptions/programming_error.html'
custom_template = 'exceptions/programming_error.html'
elif isinstance(exception, ImportError):
template_name = 'exceptions/import_error.html'
custom_template = 'exceptions/import_error.html'
elif (
sys.version_info[0] >= 3 and isinstance(exception, PermissionError)
) or (
isinstance(exception, OSError) and exception.errno == 13
):
template_name = 'exceptions/permission_error.html'
else:
template_name = '500.html'
custom_template = 'exceptions/permission_error.html'
# Return an error message
type_, error, traceback = sys.exc_info()
return render(request, template_name, {
'exception': str(type_),
'error': error,
}, status=500)
# Return a custom error message, or fall back to Django's default 500 error handling (500.html)
if custom_template:
type_, error, traceback = sys.exc_info()
template = loader.get_template(custom_template)
return HttpResponseServerError(template.render({
'exception': str(type_),
'error': error,
}))

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
from collections import OrderedDict
from copy import deepcopy
import sys
from django.conf import settings
from django.contrib import messages
@ -10,12 +11,16 @@ from django.core.exceptions import ValidationError
from django.db import transaction, IntegrityError
from django.db.models import ProtectedError
from django.forms import CharField, Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
from django.http import HttpResponseServerError
from django.shortcuts import get_object_or_404, redirect, render
from django.template.exceptions import TemplateSyntaxError
from django.template import loader
from django.template.exceptions import TemplateDoesNotExist, TemplateSyntaxError
from django.urls import reverse
from django.utils.html import escape
from django.utils.http import is_safe_url
from django.utils.safestring import mark_safe
from django.views.decorators.csrf import requires_csrf_token
from django.views.defaults import ERROR_500_TEMPLATE_NAME
from django.views.generic import View
from django_tables2 import RequestConfig
@ -858,3 +863,20 @@ class BulkComponentCreateView(View):
'table': table,
'return_url': reverse(self.default_return_url),
})
@requires_csrf_token
def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
"""
Custom 500 handler to provide additional context when rendering 500.html.
"""
try:
template = loader.get_template(template_name)
except TemplateDoesNotExist:
return HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html')
type_, error, traceback = sys.exc_info()
return HttpResponseServerError(template.render({
'exception': str(type_),
'error': error,
}))