123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- =============================
- 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): ...
- .. 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.
- .. _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|AUTH|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
- .. versionchanged:: 5.2
- The term ``AUTH`` was added.
- .. 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``.
|