mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			402 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			402 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| =============================
 | ||
| How to manage error reporting
 | ||
| =============================
 | ||
| 
 | ||
| When you're running a public site you should always turn off the
 | ||
| :setting:`DEBUG` setting. That will make your server run much faster, and will
 | ||
| also prevent malicious users from seeing details of your application that can be
 | ||
| revealed by the error pages.
 | ||
| 
 | ||
| However, running with :setting:`DEBUG` set to ``False`` means you'll never see
 | ||
| errors generated by your site -- everyone will instead see your public error
 | ||
| pages. You need to keep track of errors that occur in deployed sites, so Django
 | ||
| can be configured to create reports with details about those errors.
 | ||
| 
 | ||
| Email reports
 | ||
| =============
 | ||
| 
 | ||
| Server errors
 | ||
| -------------
 | ||
| 
 | ||
| When :setting:`DEBUG` is ``False``, Django will email the users listed in the
 | ||
| :setting:`ADMINS` setting whenever your code raises an unhandled exception and
 | ||
| results in an internal server error (strictly speaking, for any response with
 | ||
| an HTTP status code of 500 or greater). This gives the administrators immediate
 | ||
| notification of any errors. The :setting:`ADMINS` will get a description of the
 | ||
| error, a complete Python traceback, and details about the HTTP request that
 | ||
| caused the error.
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|    In order to send email, Django requires a few settings telling it
 | ||
|    how to connect to your mail server. At the very least, you'll need
 | ||
|    to specify :setting:`EMAIL_HOST` and possibly
 | ||
|    :setting:`EMAIL_HOST_USER` and :setting:`EMAIL_HOST_PASSWORD`,
 | ||
|    though other settings may be also required depending on your mail
 | ||
|    server's configuration. Consult :doc:`the Django settings
 | ||
|    documentation </ref/settings>` for a full list of email-related
 | ||
|    settings.
 | ||
| 
 | ||
| By default, Django will send email from root@localhost. However, some mail
 | ||
| providers reject all email from this address. To use a different sender
 | ||
| address, modify the :setting:`SERVER_EMAIL` setting.
 | ||
| 
 | ||
| To activate this behavior, put the email addresses of the recipients in the
 | ||
| :setting:`ADMINS` setting.
 | ||
| 
 | ||
| .. seealso::
 | ||
| 
 | ||
|     Server error emails are sent using the logging framework, so you can
 | ||
|     customize this behavior by :doc:`customizing your logging configuration
 | ||
|     </topics/logging>`.
 | ||
| 
 | ||
| 404 errors
 | ||
| ----------
 | ||
| 
 | ||
| Django can also be configured to email errors about broken links (404 "page
 | ||
| not found" errors). Django sends emails about 404 errors when:
 | ||
| 
 | ||
| * :setting:`DEBUG` is ``False``;
 | ||
| 
 | ||
| * Your :setting:`MIDDLEWARE` setting includes
 | ||
|   :class:`django.middleware.common.BrokenLinkEmailsMiddleware`.
 | ||
| 
 | ||
| If those conditions are met, Django will email the users listed in the
 | ||
| :setting:`MANAGERS` setting whenever your code raises a 404 and the request has
 | ||
| a referer. It doesn't bother to email for 404s that don't have a referer --
 | ||
| those are usually people typing in broken URLs or broken web bots. It also
 | ||
| ignores 404s when the referer is equal to the requested URL, since this
 | ||
| behavior is from broken web bots too.
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|     :class:`~django.middleware.common.BrokenLinkEmailsMiddleware` must appear
 | ||
|     before other middleware that intercepts 404 errors, such as
 | ||
|     :class:`~django.middleware.locale.LocaleMiddleware` or
 | ||
|     :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`.
 | ||
|     Put it toward the top of your :setting:`MIDDLEWARE` setting.
 | ||
| 
 | ||
| You can tell Django to stop reporting particular 404s by tweaking the
 | ||
| :setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled
 | ||
| regular expression objects. For example::
 | ||
| 
 | ||
|     import re
 | ||
| 
 | ||
|     IGNORABLE_404_URLS = [
 | ||
|         re.compile(r"\.(php|cgi)$"),
 | ||
|         re.compile(r"^/phpmyadmin/"),
 | ||
|     ]
 | ||
| 
 | ||
| In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
 | ||
| reported. Neither will any URL starting with ``/phpmyadmin/``.
 | ||
| 
 | ||
| The following example shows how to exclude some conventional URLs that browsers and
 | ||
| crawlers often request::
 | ||
| 
 | ||
|     import re
 | ||
| 
 | ||
|     IGNORABLE_404_URLS = [
 | ||
|         re.compile(r"^/apple-touch-icon.*\.png$"),
 | ||
|         re.compile(r"^/favicon\.ico$"),
 | ||
|         re.compile(r"^/robots\.txt$"),
 | ||
|     ]
 | ||
| 
 | ||
| (Note that these are regular expressions, so we put a backslash in front of
 | ||
| periods to escape them.)
 | ||
| 
 | ||
| If you'd like to customize the behavior of
 | ||
| :class:`django.middleware.common.BrokenLinkEmailsMiddleware` further (for
 | ||
| example to ignore requests coming from web crawlers), you should subclass it
 | ||
| and override its methods.
 | ||
| 
 | ||
| .. seealso::
 | ||
| 
 | ||
|     404 errors are logged using the logging framework. By default, these log
 | ||
|     records are ignored, but you can use them for error reporting by writing a
 | ||
|     handler and :doc:`configuring logging </topics/logging>` appropriately.
 | ||
| 
 | ||
| .. _filtering-error-reports:
 | ||
| 
 | ||
| Filtering error reports
 | ||
| =======================
 | ||
| 
 | ||
| .. warning::
 | ||
| 
 | ||
|     Filtering sensitive data is a hard problem, and it's nearly impossible to
 | ||
|     guarantee that sensitive data won't leak into an error report. Therefore,
 | ||
|     error reports should only be available to trusted team members and you
 | ||
|     should avoid transmitting error reports unencrypted over the internet
 | ||
|     (such as through email).
 | ||
| 
 | ||
| Filtering sensitive information
 | ||
| -------------------------------
 | ||
| 
 | ||
| .. currentmodule:: django.views.decorators.debug
 | ||
| 
 | ||
| Error reports are really helpful for debugging errors, so it is generally
 | ||
| useful to record as much relevant information about those errors as possible.
 | ||
| For example, by default Django records the `full traceback`_ for the
 | ||
| exception raised, each `traceback frame`_’s local variables, and the
 | ||
| :class:`~django.http.HttpRequest`’s :ref:`attributes<httprequest-attributes>`.
 | ||
| 
 | ||
| However, sometimes certain types of information may be too sensitive and thus
 | ||
| may not be appropriate to be kept track of, for example a user's password or
 | ||
| credit card number. So in addition to filtering out settings that appear to be
 | ||
| sensitive as described in the :setting:`DEBUG` documentation, Django offers a
 | ||
| set of function decorators to help you control which information should be
 | ||
| filtered out of error reports in a production environment (that is, where
 | ||
| :setting:`DEBUG` is set to ``False``): :func:`sensitive_variables` and
 | ||
| :func:`sensitive_post_parameters`.
 | ||
| 
 | ||
| .. _`full traceback`: https://en.wikipedia.org/wiki/Stack_trace
 | ||
| .. _`traceback frame`: https://en.wikipedia.org/wiki/Stack_frame
 | ||
| 
 | ||
| .. function:: sensitive_variables(*variables)
 | ||
| 
 | ||
|     If a function (either a view or any regular callback) in your code uses
 | ||
|     local variables susceptible to contain sensitive information, you may
 | ||
|     prevent the values of those variables from being included in error reports
 | ||
|     using the ``sensitive_variables`` decorator::
 | ||
| 
 | ||
|         from django.views.decorators.debug import sensitive_variables
 | ||
| 
 | ||
| 
 | ||
|         @sensitive_variables("user", "pw", "cc")
 | ||
|         def process_info(user):
 | ||
|             pw = user.pass_word
 | ||
|             cc = user.credit_card_number
 | ||
|             name = user.name
 | ||
|             ...
 | ||
| 
 | ||
|     In the above example, the values for the ``user``, ``pw`` and ``cc``
 | ||
|     variables will be hidden and replaced with stars (``**********``)
 | ||
|     in the error reports, whereas the value of the ``name`` variable will be
 | ||
|     disclosed.
 | ||
| 
 | ||
|     To systematically hide all local variables of a function from error logs,
 | ||
|     do not provide any argument to the ``sensitive_variables`` decorator::
 | ||
| 
 | ||
|         @sensitive_variables()
 | ||
|         def my_function():
 | ||
|             ...
 | ||
| 
 | ||
|     .. admonition:: When using multiple decorators
 | ||
| 
 | ||
|         If the variable you want to hide is also a function argument (e.g.
 | ||
|         '``user``’ in the following example), and if the decorated function has
 | ||
|         multiple decorators, then make sure to place ``@sensitive_variables``
 | ||
|         at the top of the decorator chain. This way it will also hide the
 | ||
|         function argument as it gets passed through the other decorators::
 | ||
| 
 | ||
|             @sensitive_variables("user", "pw", "cc")
 | ||
|             @some_decorator
 | ||
|             @another_decorator
 | ||
|             def process_info(user):
 | ||
|                 ...
 | ||
| 
 | ||
|     .. warning::
 | ||
| 
 | ||
|         Due to the machinery needed to cross the sync/async boundary,
 | ||
|         :func:`~asgiref.sync.sync_to_async` and
 | ||
|         :func:`~asgiref.sync.async_to_sync` are **not** compatible with
 | ||
|         ``sensitive_variables()``.
 | ||
| 
 | ||
|         If using these adapters with sensitive variables, ensure to audit
 | ||
|         exception reporting, and consider implementing a :ref:`custom filter
 | ||
|         <custom-error-reports>` if necessary.
 | ||
| 
 | ||
|     .. versionchanged:: 5.0
 | ||
| 
 | ||
|         Support for wrapping ``async`` functions was added.
 | ||
| 
 | ||
| .. function:: sensitive_post_parameters(*parameters)
 | ||
| 
 | ||
|     If one of your views receives an :class:`~django.http.HttpRequest` object
 | ||
|     with :attr:`POST parameters<django.http.HttpRequest.POST>` susceptible to
 | ||
|     contain sensitive information, you may prevent the values of those
 | ||
|     parameters from being included in the error reports using the
 | ||
|     ``sensitive_post_parameters`` decorator::
 | ||
| 
 | ||
|         from django.views.decorators.debug import sensitive_post_parameters
 | ||
| 
 | ||
| 
 | ||
|         @sensitive_post_parameters("pass_word", "credit_card_number")
 | ||
|         def record_user_profile(request):
 | ||
|             UserProfile.create(
 | ||
|                 user=request.user,
 | ||
|                 password=request.POST["pass_word"],
 | ||
|                 credit_card=request.POST["credit_card_number"],
 | ||
|                 name=request.POST["name"],
 | ||
|             )
 | ||
|             ...
 | ||
| 
 | ||
|     In the above example, the values for the ``pass_word`` and
 | ||
|     ``credit_card_number`` POST parameters will be hidden and replaced with
 | ||
|     stars (``**********``) in the request's representation inside the
 | ||
|     error reports, whereas the value of the ``name`` parameter will be
 | ||
|     disclosed.
 | ||
| 
 | ||
|     To systematically hide all POST parameters of a request in error reports,
 | ||
|     do not provide any argument to the ``sensitive_post_parameters`` decorator::
 | ||
| 
 | ||
|         @sensitive_post_parameters()
 | ||
|         def my_view(request):
 | ||
|             ...
 | ||
| 
 | ||
|     All POST parameters are systematically filtered out of error reports for
 | ||
|     certain :mod:`django.contrib.auth.views` views (``login``,
 | ||
|     ``password_reset_confirm``, ``password_change``, and ``add_view`` and
 | ||
|     ``user_change_password`` in the ``auth`` admin) to prevent the leaking of
 | ||
|     sensitive information such as user passwords.
 | ||
| 
 | ||
|     .. versionchanged:: 5.0
 | ||
| 
 | ||
|         Support for wrapping ``async`` functions was added.
 | ||
| 
 | ||
| .. _custom-error-reports:
 | ||
| 
 | ||
| Custom error reports
 | ||
| --------------------
 | ||
| 
 | ||
| All :func:`sensitive_variables` and :func:`sensitive_post_parameters` do is,
 | ||
| respectively, annotate the decorated function with the names of sensitive
 | ||
| variables and annotate the ``HttpRequest`` object with the names of sensitive
 | ||
| POST parameters, so that this sensitive information can later be filtered out
 | ||
| of reports when an error occurs. The actual filtering is done by Django's
 | ||
| default error reporter filter:
 | ||
| :class:`django.views.debug.SafeExceptionReporterFilter`. This filter uses the
 | ||
| decorators' annotations to replace the corresponding values with stars
 | ||
| (``**********``) when the error reports are produced. If you wish to
 | ||
| override or customize this default behavior for your entire site, you need to
 | ||
| define your own filter class and tell Django to use it via the
 | ||
| :setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` setting::
 | ||
| 
 | ||
|     DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"
 | ||
| 
 | ||
| You may also control in a more granular way which filter to use within any
 | ||
| given view by setting the ``HttpRequest``’s ``exception_reporter_filter``
 | ||
| attribute::
 | ||
| 
 | ||
|     def my_view(request):
 | ||
|         if request.user.is_authenticated:
 | ||
|             request.exception_reporter_filter = CustomExceptionReporterFilter()
 | ||
|         ...
 | ||
| 
 | ||
| .. currentmodule:: django.views.debug
 | ||
| 
 | ||
| Your custom filter class needs to inherit from
 | ||
| :class:`django.views.debug.SafeExceptionReporterFilter` and may override the
 | ||
| following attributes and methods:
 | ||
| 
 | ||
| .. class:: SafeExceptionReporterFilter
 | ||
| 
 | ||
|     .. attribute:: cleansed_substitute
 | ||
| 
 | ||
|         The string value to replace sensitive value with. By default it
 | ||
|         replaces the values of sensitive variables with stars
 | ||
|         (``**********``).
 | ||
| 
 | ||
|     .. attribute:: hidden_settings
 | ||
| 
 | ||
|         A compiled regular expression object used to match settings and
 | ||
|         ``request.META`` values considered as sensitive. By default equivalent
 | ||
|         to::
 | ||
| 
 | ||
|             import re
 | ||
| 
 | ||
|             re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
 | ||
| 
 | ||
|     .. method:: is_active(request)
 | ||
| 
 | ||
|         Returns ``True`` to activate the filtering in
 | ||
|         :meth:`get_post_parameters` and :meth:`get_traceback_frame_variables`.
 | ||
|         By default the filter is active if :setting:`DEBUG` is ``False``. Note
 | ||
|         that sensitive ``request.META`` values are always filtered along with
 | ||
|         sensitive setting values, as described in the :setting:`DEBUG`
 | ||
|         documentation.
 | ||
| 
 | ||
|     .. method:: get_post_parameters(request)
 | ||
| 
 | ||
|         Returns the filtered dictionary of POST parameters. Sensitive values
 | ||
|         are replaced with :attr:`cleansed_substitute`.
 | ||
| 
 | ||
|     .. method:: get_traceback_frame_variables(request, tb_frame)
 | ||
| 
 | ||
|         Returns the filtered dictionary of local variables for the given
 | ||
|         traceback frame. Sensitive values are replaced with
 | ||
|         :attr:`cleansed_substitute`.
 | ||
| 
 | ||
| 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
 | ||
| 
 | ||
|     .. attribute:: html_template_path
 | ||
| 
 | ||
|         Property that returns a :class:`pathlib.Path` representing the absolute
 | ||
|         filesystem path to a template for rendering the HTML representation of
 | ||
|         the exception. Defaults to the Django provided template.
 | ||
| 
 | ||
|     .. attribute:: text_template_path
 | ||
| 
 | ||
|         Property that returns a :class:`pathlib.Path` representing the absolute
 | ||
|         filesystem path to a template for rendering the plain-text
 | ||
|         representation of the exception. Defaults to the Django provided
 | ||
|         template.
 | ||
| 
 | ||
|     .. 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
 | ||
|     :ref:`exception middleware <exception-middleware>`. If you do write custom
 | ||
|     error handling, it's a good idea to emulate Django's built-in error handling
 | ||
|     and only report/log errors if :setting:`DEBUG` is ``False``.
 |