1. =============================
    
  2. How to manage error reporting
    
  3. =============================
    
  4. 
    
  5. When you're running a public site you should always turn off the
    
  6. :setting:`DEBUG` setting. That will make your server run much faster, and will
    
  7. also prevent malicious users from seeing details of your application that can be
    
  8. revealed by the error pages.
    
  9. 
    
  10. However, running with :setting:`DEBUG` set to ``False`` means you'll never see
    
  11. errors generated by your site -- everyone will instead see your public error
    
  12. pages. You need to keep track of errors that occur in deployed sites, so Django
    
  13. can be configured to create reports with details about those errors.
    
  14. 
    
  15. Email reports
    
  16. =============
    
  17. 
    
  18. Server errors
    
  19. -------------
    
  20. 
    
  21. When :setting:`DEBUG` is ``False``, Django will email the users listed in the
    
  22. :setting:`ADMINS` setting whenever your code raises an unhandled exception and
    
  23. results in an internal server error (strictly speaking, for any response with
    
  24. an HTTP status code of 500 or greater). This gives the administrators immediate
    
  25. notification of any errors. The :setting:`ADMINS` will get a description of the
    
  26. error, a complete Python traceback, and details about the HTTP request that
    
  27. caused the error.
    
  28. 
    
  29. .. note::
    
  30. 
    
  31.    In order to send email, Django requires a few settings telling it
    
  32.    how to connect to your mail server. At the very least, you'll need
    
  33.    to specify :setting:`EMAIL_HOST` and possibly
    
  34.    :setting:`EMAIL_HOST_USER` and :setting:`EMAIL_HOST_PASSWORD`,
    
  35.    though other settings may be also required depending on your mail
    
  36.    server's configuration. Consult :doc:`the Django settings
    
  37.    documentation </ref/settings>` for a full list of email-related
    
  38.    settings.
    
  39. 
    
  40. By default, Django will send email from root@localhost. However, some mail
    
  41. providers reject all email from this address. To use a different sender
    
  42. address, modify the :setting:`SERVER_EMAIL` setting.
    
  43. 
    
  44. To activate this behavior, put the email addresses of the recipients in the
    
  45. :setting:`ADMINS` setting.
    
  46. 
    
  47. .. seealso::
    
  48. 
    
  49.     Server error emails are sent using the logging framework, so you can
    
  50.     customize this behavior by :doc:`customizing your logging configuration
    
  51.     </topics/logging>`.
    
  52. 
    
  53. 404 errors
    
  54. ----------
    
  55. 
    
  56. Django can also be configured to email errors about broken links (404 "page
    
  57. not found" errors). Django sends emails about 404 errors when:
    
  58. 
    
  59. * :setting:`DEBUG` is ``False``;
    
  60. 
    
  61. * Your :setting:`MIDDLEWARE` setting includes
    
  62.   :class:`django.middleware.common.BrokenLinkEmailsMiddleware`.
    
  63. 
    
  64. If those conditions are met, Django will email the users listed in the
    
  65. :setting:`MANAGERS` setting whenever your code raises a 404 and the request has
    
  66. a referer. It doesn't bother to email for 404s that don't have a referer --
    
  67. those are usually people typing in broken URLs or broken web bots. It also
    
  68. ignores 404s when the referer is equal to the requested URL, since this
    
  69. behavior is from broken web bots too.
    
  70. 
    
  71. .. note::
    
  72. 
    
  73.     :class:`~django.middleware.common.BrokenLinkEmailsMiddleware` must appear
    
  74.     before other middleware that intercepts 404 errors, such as
    
  75.     :class:`~django.middleware.locale.LocaleMiddleware` or
    
  76.     :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`.
    
  77.     Put it toward the top of your :setting:`MIDDLEWARE` setting.
    
  78. 
    
  79. You can tell Django to stop reporting particular 404s by tweaking the
    
  80. :setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled
    
  81. regular expression objects. For example::
    
  82. 
    
  83.     import re
    
  84.     IGNORABLE_404_URLS = [
    
  85.         re.compile(r'\.(php|cgi)$'),
    
  86.         re.compile(r'^/phpmyadmin/'),
    
  87.     ]
    
  88. 
    
  89. In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
    
  90. reported. Neither will any URL starting with ``/phpmyadmin/``.
    
  91. 
    
  92. The following example shows how to exclude some conventional URLs that browsers and
    
  93. crawlers often request::
    
  94. 
    
  95.     import re
    
  96.     IGNORABLE_404_URLS = [
    
  97.         re.compile(r'^/apple-touch-icon.*\.png$'),
    
  98.         re.compile(r'^/favicon\.ico$'),
    
  99.         re.compile(r'^/robots\.txt$'),
    
  100.     ]
    
  101. 
    
  102. (Note that these are regular expressions, so we put a backslash in front of
    
  103. periods to escape them.)
    
  104. 
    
  105. If you'd like to customize the behavior of
    
  106. :class:`django.middleware.common.BrokenLinkEmailsMiddleware` further (for
    
  107. example to ignore requests coming from web crawlers), you should subclass it
    
  108. and override its methods.
    
  109. 
    
  110. .. seealso::
    
  111. 
    
  112.     404 errors are logged using the logging framework. By default, these log
    
  113.     records are ignored, but you can use them for error reporting by writing a
    
  114.     handler and :doc:`configuring logging </topics/logging>` appropriately.
    
  115. 
    
  116. .. _filtering-error-reports:
    
  117. 
    
  118. Filtering error reports
    
  119. =======================
    
  120. 
    
  121. .. warning::
    
  122. 
    
  123.     Filtering sensitive data is a hard problem, and it's nearly impossible to
    
  124.     guarantee that sensitive data won't leak into an error report. Therefore,
    
  125.     error reports should only be available to trusted team members and you
    
  126.     should avoid transmitting error reports unencrypted over the internet
    
  127.     (such as through email).
    
  128. 
    
  129. Filtering sensitive information
    
  130. -------------------------------
    
  131. 
    
  132. .. currentmodule:: django.views.decorators.debug
    
  133. 
    
  134. Error reports are really helpful for debugging errors, so it is generally
    
  135. useful to record as much relevant information about those errors as possible.
    
  136. For example, by default Django records the `full traceback`_ for the
    
  137. exception raised, each `traceback frame`_’s local variables, and the
    
  138. :class:`~django.http.HttpRequest`’s :ref:`attributes<httprequest-attributes>`.
    
  139. 
    
  140. However, sometimes certain types of information may be too sensitive and thus
    
  141. may not be appropriate to be kept track of, for example a user's password or
    
  142. credit card number. So in addition to filtering out settings that appear to be
    
  143. sensitive as described in the :setting:`DEBUG` documentation, Django offers a
    
  144. set of function decorators to help you control which information should be
    
  145. filtered out of error reports in a production environment (that is, where
    
  146. :setting:`DEBUG` is set to ``False``): :func:`sensitive_variables` and
    
  147. :func:`sensitive_post_parameters`.
    
  148. 
    
  149. .. _`full traceback`: https://en.wikipedia.org/wiki/Stack_trace
    
  150. .. _`traceback frame`: https://en.wikipedia.org/wiki/Stack_frame
    
  151. 
    
  152. .. function:: sensitive_variables(*variables)
    
  153. 
    
  154.     If a function (either a view or any regular callback) in your code uses
    
  155.     local variables susceptible to contain sensitive information, you may
    
  156.     prevent the values of those variables from being included in error reports
    
  157.     using the ``sensitive_variables`` decorator::
    
  158. 
    
  159.         from django.views.decorators.debug import sensitive_variables
    
  160. 
    
  161.         @sensitive_variables('user', 'pw', 'cc')
    
  162.         def process_info(user):
    
  163.             pw = user.pass_word
    
  164.             cc = user.credit_card_number
    
  165.             name = user.name
    
  166.             ...
    
  167. 
    
  168.     In the above example, the values for the ``user``, ``pw`` and ``cc``
    
  169.     variables will be hidden and replaced with stars (``**********``)
    
  170.     in the error reports, whereas the value of the ``name`` variable will be
    
  171.     disclosed.
    
  172. 
    
  173.     To systematically hide all local variables of a function from error logs,
    
  174.     do not provide any argument to the ``sensitive_variables`` decorator::
    
  175. 
    
  176.         @sensitive_variables()
    
  177.         def my_function():
    
  178.             ...
    
  179. 
    
  180.     .. admonition:: When using multiple decorators
    
  181. 
    
  182.         If the variable you want to hide is also a function argument (e.g.
    
  183.         '``user``’ in the following example), and if the decorated function has
    
  184.         multiple decorators, then make sure to place ``@sensitive_variables``
    
  185.         at the top of the decorator chain. This way it will also hide the
    
  186.         function argument as it gets passed through the other decorators::
    
  187. 
    
  188.             @sensitive_variables('user', 'pw', 'cc')
    
  189.             @some_decorator
    
  190.             @another_decorator
    
  191.             def process_info(user):
    
  192.                 ...
    
  193. 
    
  194. .. function:: sensitive_post_parameters(*parameters)
    
  195. 
    
  196.     If one of your views receives an :class:`~django.http.HttpRequest` object
    
  197.     with :attr:`POST parameters<django.http.HttpRequest.POST>` susceptible to
    
  198.     contain sensitive information, you may prevent the values of those
    
  199.     parameters from being included in the error reports using the
    
  200.     ``sensitive_post_parameters`` decorator::
    
  201. 
    
  202.         from django.views.decorators.debug import sensitive_post_parameters
    
  203. 
    
  204.         @sensitive_post_parameters('pass_word', 'credit_card_number')
    
  205.         def record_user_profile(request):
    
  206.             UserProfile.create(
    
  207.                 user=request.user,
    
  208.                 password=request.POST['pass_word'],
    
  209.                 credit_card=request.POST['credit_card_number'],
    
  210.                 name=request.POST['name'],
    
  211.             )
    
  212.             ...
    
  213. 
    
  214.     In the above example, the values for the ``pass_word`` and
    
  215.     ``credit_card_number`` POST parameters will be hidden and replaced with
    
  216.     stars (``**********``) in the request's representation inside the
    
  217.     error reports, whereas the value of the ``name`` parameter will be
    
  218.     disclosed.
    
  219. 
    
  220.     To systematically hide all POST parameters of a request in error reports,
    
  221.     do not provide any argument to the ``sensitive_post_parameters`` decorator::
    
  222. 
    
  223.         @sensitive_post_parameters()
    
  224.         def my_view(request):
    
  225.             ...
    
  226. 
    
  227.     All POST parameters are systematically filtered out of error reports for
    
  228.     certain :mod:`django.contrib.auth.views` views (``login``,
    
  229.     ``password_reset_confirm``, ``password_change``, and ``add_view`` and
    
  230.     ``user_change_password`` in the ``auth`` admin) to prevent the leaking of
    
  231.     sensitive information such as user passwords.
    
  232. 
    
  233. .. _custom-error-reports:
    
  234. 
    
  235. Custom error reports
    
  236. --------------------
    
  237. 
    
  238. All :func:`sensitive_variables` and :func:`sensitive_post_parameters` do is,
    
  239. respectively, annotate the decorated function with the names of sensitive
    
  240. variables and annotate the ``HttpRequest`` object with the names of sensitive
    
  241. POST parameters, so that this sensitive information can later be filtered out
    
  242. of reports when an error occurs. The actual filtering is done by Django's
    
  243. default error reporter filter:
    
  244. :class:`django.views.debug.SafeExceptionReporterFilter`. This filter uses the
    
  245. decorators' annotations to replace the corresponding values with stars
    
  246. (``**********``) when the error reports are produced. If you wish to
    
  247. override or customize this default behavior for your entire site, you need to
    
  248. define your own filter class and tell Django to use it via the
    
  249. :setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` setting::
    
  250. 
    
  251.     DEFAULT_EXCEPTION_REPORTER_FILTER = 'path.to.your.CustomExceptionReporterFilter'
    
  252. 
    
  253. You may also control in a more granular way which filter to use within any
    
  254. given view by setting the ``HttpRequest``’s ``exception_reporter_filter``
    
  255. attribute::
    
  256. 
    
  257.     def my_view(request):
    
  258.         if request.user.is_authenticated:
    
  259.             request.exception_reporter_filter = CustomExceptionReporterFilter()
    
  260.         ...
    
  261. 
    
  262. .. currentmodule:: django.views.debug
    
  263. 
    
  264. Your custom filter class needs to inherit from
    
  265. :class:`django.views.debug.SafeExceptionReporterFilter` and may override the
    
  266. following attributes and methods:
    
  267. 
    
  268. .. class:: SafeExceptionReporterFilter
    
  269. 
    
  270.     .. attribute:: cleansed_substitute
    
  271. 
    
  272.         The string value to replace sensitive value with. By default it
    
  273.         replaces the values of sensitive variables with stars
    
  274.         (``**********``).
    
  275. 
    
  276.     .. attribute:: hidden_settings
    
  277. 
    
  278.         A compiled regular expression object used to match settings and
    
  279.         ``request.META`` values considered as sensitive. By default equivalent
    
  280.         to::
    
  281. 
    
  282.             import re
    
  283. 
    
  284.             re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.IGNORECASE)
    
  285. 
    
  286.     .. method:: is_active(request)
    
  287. 
    
  288.         Returns ``True`` to activate the filtering in
    
  289.         :meth:`get_post_parameters` and :meth:`get_traceback_frame_variables`.
    
  290.         By default the filter is active if :setting:`DEBUG` is ``False``. Note
    
  291.         that sensitive ``request.META`` values are always filtered along with
    
  292.         sensitive setting values, as described in the :setting:`DEBUG`
    
  293.         documentation.
    
  294. 
    
  295.     .. method:: get_post_parameters(request)
    
  296. 
    
  297.         Returns the filtered dictionary of POST parameters. Sensitive values
    
  298.         are replaced with :attr:`cleansed_substitute`.
    
  299. 
    
  300.     .. method:: get_traceback_frame_variables(request, tb_frame)
    
  301. 
    
  302.         Returns the filtered dictionary of local variables for the given
    
  303.         traceback frame. Sensitive values are replaced with
    
  304.         :attr:`cleansed_substitute`.
    
  305. 
    
  306. If you need to customize error reports beyond filtering you may specify a
    
  307. custom error reporter class by defining the
    
  308. :setting:`DEFAULT_EXCEPTION_REPORTER` setting::
    
  309. 
    
  310.     DEFAULT_EXCEPTION_REPORTER = 'path.to.your.CustomExceptionReporter'
    
  311. 
    
  312. The exception reporter is responsible for compiling the exception report data,
    
  313. and formatting it as text or HTML appropriately. (The exception reporter uses
    
  314. :setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` when preparing the exception
    
  315. report data.)
    
  316. 
    
  317. Your custom reporter class needs to inherit from
    
  318. :class:`django.views.debug.ExceptionReporter`.
    
  319. 
    
  320. .. class:: ExceptionReporter
    
  321. 
    
  322.     .. attribute:: html_template_path
    
  323. 
    
  324.         Property that returns a :class:`pathlib.Path` representing the absolute
    
  325.         filesystem path to a template for rendering the HTML representation of
    
  326.         the exception. Defaults to the Django provided template.
    
  327. 
    
  328.     .. attribute:: text_template_path
    
  329. 
    
  330.         Property that returns a :class:`pathlib.Path` representing the absolute
    
  331.         filesystem path to a template for rendering the plain-text
    
  332.         representation of the exception. Defaults to the Django provided
    
  333.         template.
    
  334. 
    
  335.     .. method:: get_traceback_data()
    
  336. 
    
  337.         Return a dictionary containing traceback information.
    
  338. 
    
  339.         This is the main extension point for customizing exception reports, for
    
  340.         example::
    
  341. 
    
  342.             from django.views.debug import ExceptionReporter
    
  343. 
    
  344. 
    
  345.             class CustomExceptionReporter(ExceptionReporter):
    
  346.                 def get_traceback_data(self):
    
  347.                     data = super().get_traceback_data()
    
  348.                     # ... remove/add something here ...
    
  349.                     return data
    
  350. 
    
  351.     .. method:: get_traceback_html()
    
  352. 
    
  353.         Return HTML version of exception report.
    
  354. 
    
  355.         Used for HTML version of debug 500 HTTP error page.
    
  356. 
    
  357.     .. method:: get_traceback_text()
    
  358. 
    
  359.         Return plain text version of exception report.
    
  360. 
    
  361.         Used for plain text version of debug 500 HTTP error page and email
    
  362.         reports.
    
  363. 
    
  364. As with the filter class, you may control which exception reporter class to use
    
  365. within any given view by setting the ``HttpRequest``’s
    
  366. ``exception_reporter_class`` attribute::
    
  367. 
    
  368.     def my_view(request):
    
  369.         if request.user.is_authenticated:
    
  370.             request.exception_reporter_class = CustomExceptionReporter()
    
  371.         ...
    
  372. 
    
  373. .. seealso::
    
  374. 
    
  375.     You can also set up custom error reporting by writing a custom piece of
    
  376.     :ref:`exception middleware <exception-middleware>`. If you do write custom
    
  377.     error handling, it's a good idea to emulate Django's built-in error handling
    
  378.     and only report/log errors if :setting:`DEBUG` is ``False``.