| 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:: |
| |
| 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:: |
| |
| 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 |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| .. 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 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:: |
| |
| 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 mutiple 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 |
| mutiple 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): |
| ... |
| |
| .. note:: |
| |
| .. versionchanged:: 1.4 |
| |
| Since version 1.4, 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 methods: |
| |
| .. class:: SafeExceptionReporterFilter |
| |
| .. method:: SafeExceptionReporterFilter.is_active(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(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(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(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``. |