Refs #32880 -- Renamed/reordered logging topic sections.

Moved sections so that how-to type material is all together, and
renamed headings so it's clearer what those sections are about, in
anticipation of creating a separate how-to document and expanding
the material.
This commit is contained in:
Daniele Procida 2021-06-30 18:29:25 +02:00 committed by Mariusz Felisiak
parent 261ca6ce2e
commit 62988afbea
1 changed files with 117 additions and 138 deletions

View File

@ -6,6 +6,12 @@ Logging
:ref:`Django logging reference <logging_ref>`.
Python programmers will often use ``print()`` in their code as a quick and
convenient debugging tool. Using the logging framework is only a little more
effort than that, but it's much more elegant and flexible. As well as being
useful for debugging, logging can also provide you with more - and better
structured - information about the state and health of your application.
Overview
========
@ -117,125 +123,40 @@ of a Python formatting string containing
:ref:`LogRecord attributes <python:logrecord-attributes>`; however,
you can also write custom formatters to implement specific formatting behavior.
.. _logging-how-to:
.. _logging-security-implications:
How to use logging
==================
Security implications
=====================
Django provides a :ref:`default logging configuration
<default-logging-configuration>`, that for example generates the messages that
appear in the console when using the :djadmin:`runserver`.
The logging system handles potentially sensitive information. For example, the
log record may contain information about a web request or a stack trace, while
some of the data you collect in your own loggers may also have security
implications. You need to be sure you know:
Make a basic logging call
-------------------------
* what information is collected
* where it will subsequently be stored
* how it will be transferred
* who might have access to it.
Python programmers will often use ``print()`` in their code as a quick and
convenient debugging tool. Using the logging framework is only a little more
effort than that, but it's much more elegant and flexible. As well as being
useful for debugging, logging can also provide you with more - and better
structured - information about the state and health of your application.
To help control the collection of sensitive information, you can explicitly
designate certain sensitive information to be filtered out of error reports --
read more about how to :ref:`filter error reports <filtering-error-reports>`.
To send a log message from within your code, you place a logging call into it.
``AdminEmailHandler``
---------------------
.. admonition:: Don't be tempted to use logging calls in ``settings.py``
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``).
The way that Django logging is configured as part of the ``setup()``
function means that logging calls placed in ``settings.py`` may not work as
expected, because *logging will not be set up at that point*. To explore
logging, use a view function as suggested in the example below.
First, import the Python logging library, and then obtain a logger instance
with :py:func:`logging.getLogger`. The ``getLogger()`` method must be provided
with a name. A good option is to use ``__name__``, which will provide the name
of the current Python module (see :ref:`naming-loggers` for use of explicit
naming)::
import logging
logger = logging.getLogger(__name__)
And then in a function, for example in a view, send a message to the logger::
def some_view(request):
...
if some_risky_state:
logger.warning('Platform is running at risk')
When this code is executed, that message will be sent to the logger (and if
you're using Django's default logging configuration, it will appear in the
console).
The ``WARNING`` level used in the example above is one of several
:ref:`logging severity levels <topic-logging-parts-loggers>`: ``DEBUG``,
``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``. So, another example might be::
logger.critical('Payment system is not responding')
The default logging configuration, which Django inherits from the Python
logging module, prints all messages of level ``WARNING`` and higher to the
console. Django's own defaults will *not* pass ``INFO`` or lower severity
messages from applications other than Django itself to the console - that will
need to be configured explicitly.
.. _naming-loggers:
Naming loggers
--------------
The call to :func:`logging.getLogger()` obtains (creating, if
necessary) an instance of a logger. The logger instance is identified
by a name. This name is used to identify the logger for configuration
purposes.
By convention, the logger name is usually ``__name__``, the name of
the Python module that contains the logger. This allows you to filter
and handle logging calls on a per-module basis. However, if you have
some other way of organizing your logging messages, you can provide
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
is a parent of the ``project.interesting`` logger.
Why is the hierarchy important? Well, because loggers can be set to
*propagate* their logging calls to their parents. In this way, you can
define a single set of handlers at the root of a logger tree, and
capture all logging calls in the subtree of loggers. A logger defined
in the ``project`` namespace will catch all logging messages issued on
the ``project.interesting`` and ``project.interesting.stuff`` loggers.
This propagation can be controlled on a per-logger basis. If
you don't want a particular logger to propagate to its parents, you
can turn off this behavior.
Making logging calls
--------------------
The logger instance contains an entry method for each of the default
log levels:
* ``logger.debug()``
* ``logger.info()``
* ``logger.warning()``
* ``logger.error()``
* ``logger.critical()``
There are two other logging calls available:
* ``logger.log()``: Manually emits a logging message with a
specific log level.
* ``logger.exception()``: Creates an ``ERROR`` level logging
message wrapping the current exception stack frame.
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
services to which detailed logs can be sent to get the best of multiple worlds
-- the rich information of full tracebacks, clear management of who is notified
and has access to the information, and so on.
.. _configuring-logging:
@ -537,37 +458,95 @@ 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.
.. _logging-security-implications:
.. _logging-how-to:
Security implications
=====================
How to use logging
==================
The logging system handles potentially sensitive information. For example, the
log record may contain information about a web request or a stack trace, while
some of the data you collect in your own loggers may also have security
implications. You need to be sure you know:
Django provides a :ref:`default logging configuration
<default-logging-configuration>`, so you don't need to provide any additional
configuration in order to start using logging (it's the default configuration
that for example generates the messages that appear in the console when using
the :djadmin:`runserver`).
* what information is collected
* where it will subsequently be stored
* how it will be transferred
* who might have access to it.
Make a basic logging call
-------------------------
To help control the collection of sensitive information, you can explicitly
designate certain sensitive information to be filtered out of error reports --
read more about how to :ref:`filter error reports <filtering-error-reports>`.
To send a log message from within your code, you place a logging call into it.
``AdminEmailHandler``
.. admonition:: Don't be tempted to use logging calls in ``settings.py``
The way that Django logging is configured as part of the ``setup()``
function means that logging calls placed in ``settings.py`` may not work as
expected, because *logging will not be set up at that point*. To explore
logging, use a view function as suggested in the example below.
First, import the Python logging library, and then obtain a logger instance
with :py:func:`logging.getLogger`. The ``getLogger()`` method must be provided
with a name. A good option is to use ``__name__``, which will provide the name
of the current Python module (see :ref:`naming-loggers` for use of explicit
naming)::
import logging
logger = logging.getLogger(__name__)
And then in a function, for example in a view, send a message to the logger::
def some_view(request):
...
if some_risky_state:
logger.warning('Platform is running at risk')
When this code is executed, that message will be sent to the logger (and if
you're using Django's default logging configuration, it will appear in the
console).
The ``WARNING`` level used in the example above is one of several
:ref:`logging severity levels <topic-logging-parts-loggers>`: ``DEBUG``,
``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``. So, another example might be::
logger.critical('Payment system is not responding')
The default logging configuration, which Django inherits from the Python
logging module, prints all messages of level ``WARNING`` and higher to the
console. Django's own defaults will *not* pass ``INFO`` or lower severity
messages from applications other than Django itself to the console - that will
need to be configured explicitly.
.. _naming-loggers:
Name logger instances
---------------------
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``).
Every logger instance has a name. By convention, the logger name is usually
``__name__``, the name of the Python module in which
:func:`logging.getLogger()` is called. This allows you to filter and handle
logging calls on a per-module basis. However, if you have some other way of
organizing your logging messages, you can provide any dot-separated name to
identify your logger::
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
services to which detailed logs can be sent to get the best of multiple worlds
-- the rich information of full tracebacks, clear management of who is notified
and has access to the information, and so on.
# 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 is a parent of the
``project.interesting`` logger. (Note that this hierarchy does not need to
reflect the actual Python module hierarchy.)
Why is the hierarchy important? Well, because loggers can be set to
*propagate* their logging calls to their parents. In this way, you can
define a single set of handlers at the root of a logger tree, and
capture all logging calls in the subtree of loggers. A logger defined
in the ``project`` namespace will catch all logging messages issued on
the ``project.interesting`` and ``project.interesting.stuff`` loggers.
This propagation can be controlled on a per-logger basis. If
you don't want a particular logger to propagate to its parents, you
can turn off this behavior.