286 lines
11 KiB
Plaintext
286 lines
11 KiB
Plaintext
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 just 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 (HTTP status code 500). 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 disable this behavior, just remove all entries from the :setting:`ADMINS`
|
|
setting.
|
|
|
|
.. seealso::
|
|
|
|
.. versionadded:: 1.3
|
|
|
|
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``
|
|
|
|
* :setting:`SEND_BROKEN_LINK_EMAILS` is ``True``
|
|
|
|
* Your :setting:`MIDDLEWARE_CLASSES` setting includes ``CommonMiddleware``
|
|
(which it does by default).
|
|
|
|
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 just people typing in broken URLs or broken Web 'bots).
|
|
|
|
You can tell Django to stop reporting particular 404s by tweaking the
|
|
:setting:`IGNORABLE_404_URLS` setting. It should be a tuple 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.)
|
|
|
|
The best way to disable this behavior is to set
|
|
:setting:`SEND_BROKEN_LINK_EMAILS` to ``False``.
|
|
|
|
.. seealso::
|
|
|
|
.. versionadded:: 1.3
|
|
|
|
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.
|
|
|
|
.. seealso::
|
|
|
|
.. versionchanged:: 1.4
|
|
|
|
Previously, two settings were used to control which URLs not to report:
|
|
:setting:`IGNORABLE_404_STARTS` and :setting:`IGNORABLE_404_ENDS`. They
|
|
were replaced by :setting:`IGNORABLE_404_URLS`.
|
|
|
|
.. _filtering-error-reports:
|
|
|
|
Filtering error reports
|
|
-----------------------
|
|
|
|
.. versionadded:: 1.4
|
|
|
|
Filtering sensitive information
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
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:`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 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`: http://en.wikipedia.org/wiki/Stack_trace
|
|
.. _`traceback frame`: http://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:
|
|
|
|
.. code-block:: python
|
|
|
|
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:
|
|
|
|
.. code-block:: python
|
|
|
|
@sensitive_variables()
|
|
def my_function():
|
|
...
|
|
|
|
.. function:: sensitive_post_parameters(*parameters)
|
|
|
|
If one of your views receives an :class:`HttpRequest` object with
|
|
:attr:`POST parameters<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:
|
|
|
|
.. code-block:: python
|
|
|
|
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:
|
|
|
|
.. code-block:: python
|
|
|
|
@sensitive_post_parameters()
|
|
def my_view(request):
|
|
...
|
|
|
|
.. note::
|
|
|
|
.. versionchanged:: 1.4
|
|
|
|
Since version 1.4, all POST parameters are systematically filtered out of
|
|
error reports for certain :mod:`contrib.views.auth` 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:
|
|
|
|
.. code-block:: python
|
|
|
|
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:
|
|
|
|
.. code-block:: python
|
|
|
|
def my_view(request):
|
|
if request.user.is_authenticated():
|
|
request.exception_reporter_filter = CustomExceptionReporterFilter()
|
|
...
|
|
|
|
Your custom filter class needs to inherit from
|
|
:class:`django.views.debug.SafeExceptionReporterFilter` and may override the
|
|
following methods:
|
|
|
|
.. class:: django.views.debug.SafeExceptionReporterFilter
|
|
|
|
.. method:: SafeExceptionReporterFilter.is_active(self, request)
|
|
|
|
Returns ``True`` to activate the filtering operated in the other methods.
|
|
By default the filter is active if :setting:`DEBUG` is ``False``.
|
|
|
|
.. method:: SafeExceptionReporterFilter.get_request_repr(self, request)
|
|
|
|
Returns the representation string of the request object, that is, the
|
|
value that would be returned by ``repr(request)``, except it uses the
|
|
filtered dictionary of POST parameters as determined by
|
|
:meth:`SafeExceptionReporterFilter.get_post_parameters`.
|
|
|
|
.. method:: SafeExceptionReporterFilter.get_post_parameters(self, request)
|
|
|
|
Returns the filtered dictionary of POST parameters. By default it replaces
|
|
the values of sensitive parameters with stars (`**********`).
|
|
|
|
.. method:: SafeExceptionReporterFilter.get_traceback_frame_variables(self, request, tb_frame)
|
|
|
|
Returns the filtered dictionary of local variables for the given traceback
|
|
frame. By default it replaces the values of sensitive variables with stars
|
|
(`**********`).
|
|
|
|
.. 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``.
|