From e3d55eeb14936e82257ac6a005e9f9a06def3d00 Mon Sep 17 00:00:00 2001 From: Daniele Procida Date: Mon, 28 Jun 2021 13:02:08 +0200 Subject: [PATCH] Refs #32880 -- Moved logging reference to new document. Completed a first step in moving reference and how-to material out of the topic document. --- django/utils/log.py | 3 +- docs/ref/index.txt | 1 + docs/ref/logging.txt | 379 ++++++++++++++++++++++++++++++++++++++++ docs/topics/logging.txt | 343 +++--------------------------------- 4 files changed, 402 insertions(+), 324 deletions(-) create mode 100644 docs/ref/logging.txt diff --git a/django/utils/log.py b/django/utils/log.py index 3d3e8701c7..7c16fc6b12 100644 --- a/django/utils/log.py +++ b/django/utils/log.py @@ -13,7 +13,8 @@ request_logger = logging.getLogger('django.request') # Default logging for Django. This sends an email to the site admins on every # HTTP 500 error. Depending on DEBUG, all other log records are either sent to # the console (DEBUG=True) or discarded (DEBUG=False) by means of the -# require_debug_true filter. +# require_debug_true filter. This configuration is quoted in +# docs/ref/logging.txt; please amend it there if edited here. DEFAULT_LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/docs/ref/index.txt b/docs/ref/index.txt index 1a10e2b42c..8fc99ada81 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -16,6 +16,7 @@ API Reference exceptions files/index forms/index + logging middleware migration-operations models/index diff --git a/docs/ref/logging.txt b/docs/ref/logging.txt new file mode 100644 index 0000000000..e60583c41c --- /dev/null +++ b/docs/ref/logging.txt @@ -0,0 +1,379 @@ +.. _logging_ref: + +======= +Logging +======= + +.. module:: django.utils.log + :synopsis: Logging tools for Django applications + +Django's logging module extends Python's builtin :mod:`logging`. + +Logging is configured as part of the general Django :func:`django.setup` +function, so it's always available unless explicitly disabled. + +.. _default-logging-configuration: + +Django's default logging configuration +====================================== + +By default, Django uses Python's :ref:`logging.config.dictConfig format +`. + +Default logging conditions +-------------------------- + +The full set of default logging conditions are: + +When :setting:`DEBUG` is ``True``: + +* The ``django`` logger sends messages in the ``django`` hierarchy (except + ``django.server``) at the ``INFO`` level or higher to the console. + +When :setting:`DEBUG` is ``False``: + +* The ``django`` logger sends messages in the ``django`` hierarchy (except + ``django.server``) with ``ERROR`` or ``CRITICAL`` level to + :class:`AdminEmailHandler`. + +Independently of the value of :setting:`DEBUG`: + +* The :ref:`django-server-logger` logger sends messages at the ``INFO`` level + or higher to the console. + +All loggers except :ref:`django-server-logger` propagate logging to their +parents, up to the root ``django`` logger. The ``console`` and ``mail_admins`` +handlers are attached to the root logger to provide the behavior described +above. + +Default logging definition +-------------------------- + +The default configuration is available as ``django.utils.log.DEFAULT_LOGGING`` +and defined in :source:`django/utils/log.py`:: + + { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'formatters': { + 'django.server': { + '()': 'django.utils.log.ServerFormatter', + 'format': '[{server_time}] {message}', + 'style': '{', + } + }, + 'handlers': { + 'console': { + 'level': 'INFO', + 'filters': ['require_debug_true'], + 'class': 'logging.StreamHandler', + }, + 'django.server': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'formatter': 'django.server', + }, + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django': { + 'handlers': ['console', 'mail_admins'], + 'level': 'INFO', + }, + 'django.server': { + 'handlers': ['django.server'], + 'level': 'INFO', + 'propagate': False, + }, + } + } + +See :ref:`configuring-logging` on how to complement or replace this default +logging configuration. + +Django logging extensions +========================= + +Django provides a number of utilities to handle the particular requirements of +logging in a web server environment. + +Loggers +------- + +Django provides several built-in loggers. + +.. _django-logger: + +``django`` +~~~~~~~~~~ + +The parent logger for messages in the ``django`` :ref:`named logger hierarchy +`. Django does not post messages using this name. +Instead, it uses one of the loggers below. + +.. _django-request-logger: + +``django.request`` +~~~~~~~~~~~~~~~~~~ + +Log messages related to the handling of requests. 5XX responses are +raised as ``ERROR`` messages; 4XX responses are raised as ``WARNING`` +messages. Requests that are logged to the ``django.security`` logger aren't +logged to ``django.request``. + +Messages to this logger have the following extra context: + +* ``status_code``: The HTTP response code associated with the request. + +* ``request``: The request object that generated the logging message. + +.. _django-server-logger: + +``django.server`` +~~~~~~~~~~~~~~~~~ + +Log messages related to the handling of requests received by the server invoked +by the :djadmin:`runserver` command. HTTP 5XX responses are logged as ``ERROR`` +messages, 4XX responses are logged as ``WARNING`` messages, and everything else +is logged as ``INFO``. + +Messages to this logger have the following extra context: + +* ``status_code``: The HTTP response code associated with the request. + +* ``request``: The request object that generated the logging message. + +.. _django-template-logger: + +``django.template`` +~~~~~~~~~~~~~~~~~~~ + +Log messages related to the rendering of templates. + +* Missing context variables are logged as ``DEBUG`` messages. + +.. _django-db-logger: + +``django.db.backends`` +~~~~~~~~~~~~~~~~~~~~~~ + +Messages relating to the interaction of code with the database. For example, +every application-level SQL statement executed by a request is logged at the +``DEBUG`` level to this logger. + +Messages to this logger have the following extra context: + +* ``duration``: The time taken to execute the SQL statement. +* ``sql``: The SQL statement that was executed. +* ``params``: The parameters that were used in the SQL call. + +For performance reasons, SQL logging is only enabled when +``settings.DEBUG`` is set to ``True``, regardless of the logging +level or handlers that are installed. + +This logging does not include framework-level initialization (e.g. +``SET TIMEZONE``) or transaction management queries (e.g. ``BEGIN``, +``COMMIT``, and ``ROLLBACK``). Turn on query logging in your database if you +wish to view all database queries. + +.. _django-security-logger: + +``django.security.*`` +~~~~~~~~~~~~~~~~~~~~~ + +The security loggers will receive messages on any occurrence of +:exc:`~django.core.exceptions.SuspiciousOperation` and other security-related +errors. There is a sub-logger for each subtype of security error, including all +``SuspiciousOperation``\s. The level of the log event depends on where the +exception is handled. Most occurrences are logged as a warning, while +any ``SuspiciousOperation`` that reaches the WSGI handler will be logged as an +error. For example, when an HTTP ``Host`` header is included in a request from +a client that does not match :setting:`ALLOWED_HOSTS`, Django will return a 400 +response, and an error message will be logged to the +``django.security.DisallowedHost`` logger. + +These log events will reach the ``django`` logger by default, which mails error +events to admins when ``DEBUG=False``. Requests resulting in a 400 response due +to a ``SuspiciousOperation`` will not be logged to the ``django.request`` +logger, but only to the ``django.security`` logger. + +To silence a particular type of ``SuspiciousOperation``, you can override that +specific logger following this example:: + + 'handlers': { + 'null': { + 'class': 'logging.NullHandler', + }, + }, + 'loggers': { + 'django.security.DisallowedHost': { + 'handlers': ['null'], + 'propagate': False, + }, + }, + +Other ``django.security`` loggers not based on ``SuspiciousOperation`` are: + +* ``django.security.csrf``: For :ref:`CSRF failures `. + +``django.db.backends.schema`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Logs the SQL queries that are executed during schema changes to the database by +the :doc:`migrations framework `. Note that it won't log the +queries executed by :class:`~django.db.migrations.operations.RunPython`. +Messages to this logger have ``params`` and ``sql`` in their extra context (but +unlike ``django.db.backends``, not duration). The values have the same meaning +as explained in :ref:`django-db-logger`. + +Handlers +-------- + +Django provides one log handler in addition to those provided by the +Python logging module. + +.. class:: AdminEmailHandler(include_html=False, email_backend=None, reporter_class=None) + + This handler sends an email to the site :setting:`ADMINS` for each log + message it receives. + + If the log record contains a ``request`` attribute, the full details + of the request will be included in the email. The email subject will + include the phrase "internal IP" if the client's IP address is in the + :setting:`INTERNAL_IPS` setting; if not, it will include "EXTERNAL IP". + + If the log record contains stack trace information, that stack + trace will be included in the email. + + The ``include_html`` argument of ``AdminEmailHandler`` is used to + control whether the traceback email includes an HTML attachment + containing the full content of the debug Web page that would have been + produced if :setting:`DEBUG` were ``True``. To set this value in your + configuration, include it in the handler definition for + ``django.utils.log.AdminEmailHandler``, like this:: + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + }, + }, + + Be aware of the :ref:`security implications of logging + ` when using the ``AdminEmailHandler``. + + By setting the ``email_backend`` argument of ``AdminEmailHandler``, the + :ref:`email backend ` that is being used by the + handler can be overridden, like this:: + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'email_backend': 'django.core.mail.backends.filebased.EmailBackend', + }, + }, + + By default, an instance of the email backend specified in + :setting:`EMAIL_BACKEND` will be used. + + The ``reporter_class`` argument of ``AdminEmailHandler`` allows providing + an ``django.views.debug.ExceptionReporter`` subclass to customize the + traceback text sent in the email body. You provide a string import path to + the class you wish to use, like this:: + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + 'reporter_class': 'somepackage.error_reporter.CustomErrorReporter', + }, + }, + + .. method:: send_mail(subject, message, *args, **kwargs) + + Sends emails to admin users. To customize this behavior, you can + subclass the :class:`~django.utils.log.AdminEmailHandler` class and + override this method. + +Filters +------- + +Django provides some log filters in addition to those provided by the Python +logging module. + +.. class:: CallbackFilter(callback) + + This filter accepts a callback function (which should accept a single + argument, the record to be logged), and calls it for each record that + passes through the filter. Handling of that record will not proceed if the + callback returns False. + + For instance, to filter out :exc:`~django.http.UnreadablePostError` + (raised when a user cancels an upload) from the admin emails, you would + create a filter function:: + + from django.http import UnreadablePostError + + def skip_unreadable_post(record): + if record.exc_info: + exc_type, exc_value = record.exc_info[:2] + if isinstance(exc_value, UnreadablePostError): + return False + return True + + and then add it to your logging config:: + + 'filters': { + 'skip_unreadable_posts': { + '()': 'django.utils.log.CallbackFilter', + 'callback': skip_unreadable_post, + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['skip_unreadable_posts'], + 'class': 'django.utils.log.AdminEmailHandler', + }, + }, + +.. class:: RequireDebugFalse() + + This filter will only pass on records when settings.DEBUG is False. + + This filter is used as follows in the default :setting:`LOGGING` + configuration to ensure that the :class:`AdminEmailHandler` only sends + error emails to admins when :setting:`DEBUG` is ``False``:: + + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler', + }, + }, + +.. class:: RequireDebugTrue() + + This filter is similar to :class:`RequireDebugFalse`, except that records are + passed only when :setting:`DEBUG` is ``True``. diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index b458d0c982..47e2a6b54a 100644 --- a/docs/topics/logging.txt +++ b/docs/topics/logging.txt @@ -2,16 +2,16 @@ Logging ======= -.. module:: django.utils.log - :synopsis: Logging tools for Django applications +.. seealso:: + + :ref:`Django logging reference `. Overview ======== -Django uses Python's builtin :mod:`logging` module to perform system logging. -The usage of this module is discussed in detail in Python's own documentation. -However, if you've never used Python's logging framework (or even if you have), -here's a quick primer. +Django uses and extends Python's builtin :mod:`logging` module to perform +system logging. This module is discussed in detail in Python's own +documentation; this section provides a quick overview. The cast of players ------------------- @@ -196,6 +196,11 @@ any dot-separated name to identify your logger:: # Get an instance of a specific named logger logger = logging.getLogger('project.interesting.stuff') +.. _naming-loggers-hierarchy: + +Logger hierarchy +~~~~~~~~~~~~~~~~ + The dotted paths of logger names define a hierarchy. The ``project.interesting`` logger is considered to be a parent of the ``project.interesting.stuff`` logger; the ``project`` logger @@ -465,9 +470,9 @@ This logging configuration does the following things: (or higher) message to ``sys.stderr``. This handler uses the ``simple`` output format. - * ``mail_admins``, an :class:`AdminEmailHandler`, which emails any ``ERROR`` - (or higher) message to the site :setting:`ADMINS`. This handler uses the - ``special`` filter. + * ``mail_admins``, an :class:`~django.utils.log.AdminEmailHandler`, which + emails any ``ERROR`` (or higher) message to the site :setting:`ADMINS`. + This handler uses the ``special`` filter. * Configures three loggers: @@ -532,314 +537,6 @@ configuring the logging in your settings file will load your logging config immediately. As such, your logging config must appear *after* any settings on which it depends. -Django logging extension reference -================================== - -Django provides a number of utilities to handle the unique -requirements of logging in a web server environment. - -Loggers -------- - -Django provides several built-in loggers. - -.. _django-logger: - -``django`` -~~~~~~~~~~ - -The catch-all logger for messages in the ``django`` hierarchy. No messages are -posted using this name but instead using one of the loggers below. - -.. _django-request-logger: - -``django.request`` -~~~~~~~~~~~~~~~~~~ - -Log messages related to the handling of requests. 5XX responses are -raised as ``ERROR`` messages; 4XX responses are raised as ``WARNING`` -messages. Requests that are logged to the ``django.security`` logger aren't -logged to ``django.request``. - -Messages to this logger have the following extra context: - -* ``status_code``: The HTTP response code associated with the - request. - -* ``request``: The request object that generated the logging - message. - -.. _django-server-logger: - -``django.server`` -~~~~~~~~~~~~~~~~~ - -Log messages related to the handling of requests received by the server invoked -by the :djadmin:`runserver` command. HTTP 5XX responses are logged as ``ERROR`` -messages, 4XX responses are logged as ``WARNING`` messages, and everything else -is logged as ``INFO``. - -Messages to this logger have the following extra context: - -* ``status_code``: The HTTP response code associated with the request. - -* ``request``: The request object that generated the logging message. - -.. _django-template-logger: - -``django.template`` -~~~~~~~~~~~~~~~~~~~ - -Log messages related to the rendering of templates. - -* Missing context variables are logged as ``DEBUG`` messages. - -.. _django-db-logger: - -``django.db.backends`` -~~~~~~~~~~~~~~~~~~~~~~ - -Messages relating to the interaction of code with the database. For example, -every application-level SQL statement executed by a request is logged at the -``DEBUG`` level to this logger. - -Messages to this logger have the following extra context: - -* ``duration``: The time taken to execute the SQL statement. -* ``sql``: The SQL statement that was executed. -* ``params``: The parameters that were used in the SQL call. - -For performance reasons, SQL logging is only enabled when -``settings.DEBUG`` is set to ``True``, regardless of the logging -level or handlers that are installed. - -This logging does not include framework-level initialization (e.g. -``SET TIMEZONE``) or transaction management queries (e.g. ``BEGIN``, -``COMMIT``, and ``ROLLBACK``). Turn on query logging in your database if you -wish to view all database queries. - -.. _django-security-logger: - -``django.security.*`` -~~~~~~~~~~~~~~~~~~~~~~ - -The security loggers will receive messages on any occurrence of -:exc:`~django.core.exceptions.SuspiciousOperation` and other security-related -errors. There is a sub-logger for each subtype of security error, including all -``SuspiciousOperation``\s. The level of the log event depends on where the -exception is handled. Most occurrences are logged as a warning, while -any ``SuspiciousOperation`` that reaches the WSGI handler will be logged as an -error. For example, when an HTTP ``Host`` header is included in a request from -a client that does not match :setting:`ALLOWED_HOSTS`, Django will return a 400 -response, and an error message will be logged to the -``django.security.DisallowedHost`` logger. - -These log events will reach the ``django`` logger by default, which mails error -events to admins when ``DEBUG=False``. Requests resulting in a 400 response due -to a ``SuspiciousOperation`` will not be logged to the ``django.request`` -logger, but only to the ``django.security`` logger. - -To silence a particular type of ``SuspiciousOperation``, you can override that -specific logger following this example:: - - 'handlers': { - 'null': { - 'class': 'logging.NullHandler', - }, - }, - 'loggers': { - 'django.security.DisallowedHost': { - 'handlers': ['null'], - 'propagate': False, - }, - }, - -Other ``django.security`` loggers not based on ``SuspiciousOperation`` are: - -* ``django.security.csrf``: For :ref:`CSRF failures `. - -``django.db.backends.schema`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Logs the SQL queries that are executed during schema changes to the database by -the :doc:`migrations framework `. Note that it won't log the -queries executed by :class:`~django.db.migrations.operations.RunPython`. -Messages to this logger have ``params`` and ``sql`` in their extra context (but -unlike ``django.db.backends``, not duration). The values have the same meaning -as explained in :ref:`django-db-logger`. - -Handlers --------- - -Django provides one log handler in addition to those provided by the -Python logging module. - -.. class:: AdminEmailHandler(include_html=False, email_backend=None, reporter_class=None) - - This handler sends an email to the site :setting:`ADMINS` for each log - message it receives. - - If the log record contains a ``request`` attribute, the full details - of the request will be included in the email. The email subject will - include the phrase "internal IP" if the client's IP address is in the - :setting:`INTERNAL_IPS` setting; if not, it will include "EXTERNAL IP". - - If the log record contains stack trace information, that stack - trace will be included in the email. - - The ``include_html`` argument of ``AdminEmailHandler`` is used to - control whether the traceback email includes an HTML attachment - containing the full content of the debug Web page that would have been - produced if :setting:`DEBUG` were ``True``. To set this value in your - configuration, include it in the handler definition for - ``django.utils.log.AdminEmailHandler``, like this:: - - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', - 'include_html': True, - } - }, - - Be aware of the :ref:`security implications of logging - ` when using the ``AdminEmailHandler``. - - By setting the ``email_backend`` argument of ``AdminEmailHandler``, the - :ref:`email backend ` that is being used by the - handler can be overridden, like this:: - - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', - 'email_backend': 'django.core.mail.backends.filebased.EmailBackend', - } - }, - - By default, an instance of the email backend specified in - :setting:`EMAIL_BACKEND` will be used. - - The ``reporter_class`` argument of ``AdminEmailHandler`` allows providing - an ``django.views.debug.ExceptionReporter`` subclass to customize the - traceback text sent in the email body. You provide a string import path to - the class you wish to use, like this:: - - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'class': 'django.utils.log.AdminEmailHandler', - 'include_html': True, - 'reporter_class': 'somepackage.error_reporter.CustomErrorReporter' - } - }, - - .. method:: send_mail(subject, message, *args, **kwargs) - - Sends emails to admin users. To customize this behavior, you can - subclass the :class:`~django.utils.log.AdminEmailHandler` class and - override this method. - -Filters -------- - -Django provides some log filters in addition to those provided by the Python -logging module. - -.. class:: CallbackFilter(callback) - - This filter accepts a callback function (which should accept a single - argument, the record to be logged), and calls it for each record that - passes through the filter. Handling of that record will not proceed if the - callback returns False. - - For instance, to filter out :exc:`~django.http.UnreadablePostError` - (raised when a user cancels an upload) from the admin emails, you would - create a filter function:: - - from django.http import UnreadablePostError - - def skip_unreadable_post(record): - if record.exc_info: - exc_type, exc_value = record.exc_info[:2] - if isinstance(exc_value, UnreadablePostError): - return False - return True - - and then add it to your logging config:: - - 'filters': { - 'skip_unreadable_posts': { - '()': 'django.utils.log.CallbackFilter', - 'callback': skip_unreadable_post, - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['skip_unreadable_posts'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - -.. class:: RequireDebugFalse() - - This filter will only pass on records when settings.DEBUG is False. - - This filter is used as follows in the default :setting:`LOGGING` - configuration to ensure that the :class:`AdminEmailHandler` only sends - error emails to admins when :setting:`DEBUG` is ``False``:: - - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse', - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - -.. class:: RequireDebugTrue() - - This filter is similar to :class:`RequireDebugFalse`, except that records are - passed only when :setting:`DEBUG` is ``True``. - -.. _default-logging-configuration: - -Django's default logging configuration -====================================== - -By default, Django configures the following logging: - -When :setting:`DEBUG` is ``True``: - -* The ``django`` logger sends messages in the ``django`` hierarchy (except - ``django.server``) at the ``INFO`` level or higher to the console. - -When :setting:`DEBUG` is ``False``: - -* The ``django`` logger sends messages in the ``django`` hierarchy (except - ``django.server``) with ``ERROR`` or ``CRITICAL`` level to - :class:`AdminEmailHandler`. - -Independent of the value of :setting:`DEBUG`: - -* The :ref:`django-server-logger` logger sends messages at the ``INFO`` level - or higher to the console. - -All loggers except :ref:`django-server-logger` propagate logging to their -parents, up to the root ``django`` logger. The ``console`` and ``mail_admins`` -handlers are attached to the root logger to provide the behavior described -above. - -See also :ref:`Configuring logging ` to learn how you can -complement or replace this default logging configuration defined in -:source:`django/utils/log.py`. - .. _logging-security-implications: Security implications @@ -862,12 +559,12 @@ read more about how to :ref:`filter error reports `. ``AdminEmailHandler`` --------------------- -The built-in :class:`AdminEmailHandler` deserves a mention in the context of -security. If its ``include_html`` option is enabled, the email message it sends -will contain a full traceback, with names and values of local variables at each -level of the stack, plus the values of your Django settings (in other words, -the same level of detail that is exposed in a web page when :setting:`DEBUG` is -``True``). +The built-in :class:`~django.utils.log.AdminEmailHandler` deserves a mention in +the context of security. If its ``include_html`` option is enabled, the email +message it sends will contain a full traceback, with names and values of local +variables at each level of the stack, plus the values of your Django settings +(in other words, the same level of detail that is exposed in a web page when +:setting:`DEBUG` is ``True``). It's generally not considered a good idea to send such potentially sensitive information over email. Consider instead using one of the many third-party