Fixed #30752 -- Allowed using ExceptionReporter subclasses in error reports.
This commit is contained in:
parent
a5a28de89d
commit
13e4abf83e
|
@ -567,6 +567,10 @@ LOGGING_CONFIG = 'logging.config.dictConfig'
|
|||
# Custom logging configuration.
|
||||
LOGGING = {}
|
||||
|
||||
# Default exception reporter class used in case none has been
|
||||
# specifically assigned to the HttpRequest instance.
|
||||
DEFAULT_EXCEPTION_REPORTER = 'django.views.debug.ExceptionReporter'
|
||||
|
||||
# Default exception reporter filter class used in case none has been
|
||||
# specifically assigned to the HttpRequest instance.
|
||||
DEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'
|
||||
|
|
|
@ -86,7 +86,7 @@ class AdminEmailHandler(logging.Handler):
|
|||
super().__init__()
|
||||
self.include_html = include_html
|
||||
self.email_backend = email_backend
|
||||
self.reporter_class = import_string(reporter_class or 'django.views.debug.ExceptionReporter')
|
||||
self.reporter_class = import_string(reporter_class or settings.DEFAULT_EXCEPTION_REPORTER)
|
||||
|
||||
def emit(self, record):
|
||||
try:
|
||||
|
|
|
@ -47,7 +47,7 @@ def technical_500_response(request, exc_type, exc_value, tb, status_code=500):
|
|||
Create a technical server error response. The last three arguments are
|
||||
the values returned from sys.exc_info() and friends.
|
||||
"""
|
||||
reporter = ExceptionReporter(request, exc_type, exc_value, tb)
|
||||
reporter = get_exception_reporter_class(request)(request, exc_type, exc_value, tb)
|
||||
if request.is_ajax():
|
||||
text = reporter.get_traceback_text()
|
||||
return HttpResponse(text, status=status_code, content_type='text/plain; charset=utf-8')
|
||||
|
@ -67,6 +67,11 @@ def get_exception_reporter_filter(request):
|
|||
return getattr(request, 'exception_reporter_filter', default_filter)
|
||||
|
||||
|
||||
def get_exception_reporter_class(request):
|
||||
default_exception_reporter_class = import_string(settings.DEFAULT_EXCEPTION_REPORTER)
|
||||
return getattr(request, 'exception_reporter_class', default_exception_reporter_class)
|
||||
|
||||
|
||||
class SafeExceptionReporterFilter:
|
||||
"""
|
||||
Use annotations made by the sensitive_post_parameters and
|
||||
|
|
|
@ -305,6 +305,62 @@ following attributes and methods:
|
|||
traceback frame. Sensitive values are replaced with
|
||||
:attr:`cleansed_substitute`.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
If you need to customize error reports beyond filtering you may specify a
|
||||
custom error reporter class by defining the
|
||||
:setting:`DEFAULT_EXCEPTION_REPORTER` setting::
|
||||
|
||||
DEFAULT_EXCEPTION_REPORTER = 'path.to.your.CustomExceptionReporter'
|
||||
|
||||
The exception reporter is responsible for compiling the exception report data,
|
||||
and formatting it as text or HTML appropriately. (The exception reporter uses
|
||||
:setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` when preparing the exception
|
||||
report data.)
|
||||
|
||||
Your custom reporter class needs to inherit from
|
||||
:class:`django.views.debug.ExceptionReporter`.
|
||||
|
||||
.. class:: ExceptionReporter
|
||||
|
||||
.. method:: get_traceback_data()
|
||||
|
||||
Return a dictionary containing traceback information.
|
||||
|
||||
This is the main extension point for customizing exception reports, for
|
||||
example::
|
||||
|
||||
from django.views.debug import ExceptionReporter
|
||||
|
||||
|
||||
class CustomExceptionReporter(ExceptionReporter):
|
||||
def get_traceback_data(self):
|
||||
data = super().get_traceback_data()
|
||||
# ... remove/add something here ...
|
||||
return data
|
||||
|
||||
.. method:: get_traceback_html()
|
||||
|
||||
Return HTML version of exception report.
|
||||
|
||||
Used for HTML version of debug 500 HTTP error page.
|
||||
|
||||
.. method:: get_traceback_text()
|
||||
|
||||
Return plain text version of exception report.
|
||||
|
||||
Used for plain text version of debug 500 HTTP error page and email
|
||||
reports.
|
||||
|
||||
As with the filter class, you may control which exception reporter class to use
|
||||
within any given view by setting the ``HttpRequest``’s
|
||||
``exception_reporter_class`` attribute::
|
||||
|
||||
def my_view(request):
|
||||
if request.user.is_authenticated:
|
||||
request.exception_reporter_class = CustomExceptionReporter()
|
||||
...
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can also set up custom error reporting by writing a custom piece of
|
||||
|
|
|
@ -1250,6 +1250,19 @@ Default: ``'utf-8'``
|
|||
Default charset to use for all ``HttpResponse`` objects, if a MIME type isn't
|
||||
manually specified. Used when constructing the ``Content-Type`` header.
|
||||
|
||||
.. setting:: DEFAULT_EXCEPTION_REPORTER
|
||||
|
||||
``DEFAULT_EXCEPTION_REPORTER``
|
||||
------------------------------
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
Default: ``'``:class:`django.views.debug.ExceptionReporter`\ ``'``
|
||||
|
||||
Default exception reporter class to be used if none has been assigned to the
|
||||
:class:`~django.http.HttpRequest` instance yet. See
|
||||
:ref:`custom-error-reports`.
|
||||
|
||||
.. setting:: DEFAULT_EXCEPTION_REPORTER_FILTER
|
||||
|
||||
``DEFAULT_EXCEPTION_REPORTER_FILTER``
|
||||
|
@ -3537,6 +3550,7 @@ Email
|
|||
|
||||
Error reporting
|
||||
---------------
|
||||
* :setting:`DEFAULT_EXCEPTION_REPORTER`
|
||||
* :setting:`DEFAULT_EXCEPTION_REPORTER_FILTER`
|
||||
* :setting:`IGNORABLE_404_URLS`
|
||||
* :setting:`MANAGERS`
|
||||
|
|
|
@ -173,6 +173,10 @@ Error Reporting
|
|||
:setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` when applying settings
|
||||
filtering.
|
||||
|
||||
* The new :setting:`DEFAULT_EXCEPTION_REPORTER` allows providing a
|
||||
:class:`django.views.debug.ExceptionReporter` subclass to customize exception
|
||||
report generation. See :ref:`custom-error-reports` for details.
|
||||
|
||||
File Storage
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -249,6 +249,15 @@ class DebugViewTests(SimpleTestCase):
|
|||
response = self.client.get('/path-post/1/')
|
||||
self.assertContains(response, 'Page not found', status_code=404)
|
||||
|
||||
def test_exception_reporter_from_request(self):
|
||||
response = self.client.get('/custom_reporter_class_view/')
|
||||
self.assertContains(response, 'custom traceback text', status_code=500)
|
||||
|
||||
@override_settings(DEFAULT_EXCEPTION_REPORTER='view_tests.views.CustomExceptionReporter')
|
||||
def test_exception_reporter_from_settings(self):
|
||||
response = self.client.get('/raises500/')
|
||||
self.assertContains(response, 'custom traceback text', status_code=500)
|
||||
|
||||
|
||||
class DebugViewQueriesAllowedTests(SimpleTestCase):
|
||||
# May need a query to initialize MySQL connection
|
||||
|
|
|
@ -26,6 +26,7 @@ urlpatterns = [
|
|||
path('raises403/', views.raises403),
|
||||
path('raises404/', views.raises404),
|
||||
path('raises500/', views.raises500),
|
||||
path('custom_reporter_class_view/', views.custom_reporter_class_view),
|
||||
|
||||
path('technical404/', views.technical404, name='my404'),
|
||||
path('classbased404/', views.Http404View.as_view()),
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.template import TemplateDoesNotExist
|
|||
from django.urls import get_resolver
|
||||
from django.views import View
|
||||
from django.views.debug import (
|
||||
SafeExceptionReporterFilter, technical_500_response,
|
||||
ExceptionReporter, SafeExceptionReporterFilter, technical_500_response,
|
||||
)
|
||||
from django.views.decorators.debug import (
|
||||
sensitive_post_parameters, sensitive_variables,
|
||||
|
@ -227,6 +227,22 @@ def custom_exception_reporter_filter_view(request):
|
|||
return technical_500_response(request, *exc_info)
|
||||
|
||||
|
||||
class CustomExceptionReporter(ExceptionReporter):
|
||||
custom_traceback_text = 'custom traceback text'
|
||||
|
||||
def get_traceback_html(self):
|
||||
return self.custom_traceback_text
|
||||
|
||||
|
||||
def custom_reporter_class_view(request):
|
||||
request.exception_reporter_class = CustomExceptionReporter
|
||||
try:
|
||||
raise Exception
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
return technical_500_response(request, *exc_info)
|
||||
|
||||
|
||||
class Klass:
|
||||
|
||||
@sensitive_variables('sauce')
|
||||
|
|
Loading…
Reference in New Issue