|
@@ -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:
|
|
|
-
|
|
|
-How to use logging
|
|
|
-==================
|
|
|
-
|
|
|
-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`.
|
|
|
-
|
|
|
-Make a basic logging call
|
|
|
--------------------------
|
|
|
-
|
|
|
-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 send a log message from within your code, you place a logging call into it.
|
|
|
-
|
|
|
-.. 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:
|
|
|
-
|
|
|
-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.
|
|
|
+.. _logging-security-implications:
|
|
|
|
|
|
-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.
|
|
|
+Security implications
|
|
|
+=====================
|
|
|
|
|
|
-Making logging calls
|
|
|
---------------------
|
|
|
+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:
|
|
|
|
|
|
-The logger instance contains an entry method for each of the default
|
|
|
-log levels:
|
|
|
+* what information is collected
|
|
|
+* where it will subsequently be stored
|
|
|
+* how it will be transferred
|
|
|
+* who might have access to it.
|
|
|
|
|
|
-* ``logger.debug()``
|
|
|
-* ``logger.info()``
|
|
|
-* ``logger.warning()``
|
|
|
-* ``logger.error()``
|
|
|
-* ``logger.critical()``
|
|
|
+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>`.
|
|
|
|
|
|
-There are two other logging calls available:
|
|
|
+``AdminEmailHandler``
|
|
|
+---------------------
|
|
|
|
|
|
-* ``logger.log()``: Manually emits a logging message with a
|
|
|
- specific log level.
|
|
|
+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``).
|
|
|
|
|
|
-* ``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.
|