123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- .. _logging-explanation:
- =======
- Logging
- =======
- .. seealso::
- * :ref:`logging-how-to`
- * :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
- ========
- 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
- -------------------
- A Python logging configuration consists of four parts:
- * :ref:`topic-logging-parts-loggers`
- * :ref:`topic-logging-parts-handlers`
- * :ref:`topic-logging-parts-filters`
- * :ref:`topic-logging-parts-formatters`
- .. _topic-logging-parts-loggers:
- Loggers
- ~~~~~~~
- A *logger* is the entry point into the logging system. Each logger is a named
- bucket to which messages can be written for processing.
- A logger is configured to have a *log level*. This log level describes
- the severity of the messages that the logger will handle. Python
- defines the following log levels:
- * ``DEBUG``: Low level system information for debugging purposes
- * ``INFO``: General system information
- * ``WARNING``: Information describing a minor problem that has
- occurred.
- * ``ERROR``: Information describing a major problem that has
- occurred.
- * ``CRITICAL``: Information describing a critical problem that has
- occurred.
- Each message that is written to the logger is a *Log Record*. Each log
- record also has a *log level* indicating the severity of that specific
- message. A log record can also contain useful metadata that describes
- the event that is being logged. This can include details such as a
- stack trace or an error code.
- When a message is given to the logger, the log level of the message is
- compared to the log level of the logger. If the log level of the
- message meets or exceeds the log level of the logger itself, the
- message will undergo further processing. If it doesn't, the message
- will be ignored.
- Once a logger has determined that a message needs to be processed,
- it is passed to a *Handler*.
- .. _topic-logging-parts-handlers:
- Handlers
- ~~~~~~~~
- The *handler* is the engine that determines what happens to each message
- in a logger. It describes a particular logging behavior, such as
- writing a message to the screen, to a file, or to a network socket.
- Like loggers, handlers also have a log level. If the log level of a
- log record doesn't meet or exceed the level of the handler, the
- handler will ignore the message.
- A logger can have multiple handlers, and each handler can have a
- different log level. In this way, it is possible to provide different
- forms of notification depending on the importance of a message. For
- example, you could install one handler that forwards ``ERROR`` and
- ``CRITICAL`` messages to a paging service, while a second handler
- logs all messages (including ``ERROR`` and ``CRITICAL`` messages) to a
- file for later analysis.
- .. _topic-logging-parts-filters:
- Filters
- ~~~~~~~
- A *filter* is used to provide additional control over which log records
- are passed from logger to handler.
- By default, any log message that meets log level requirements will be
- handled. However, by installing a filter, you can place additional
- criteria on the logging process. For example, you could install a
- filter that only allows ``ERROR`` messages from a particular source to
- be emitted.
- Filters can also be used to modify the logging record prior to being
- emitted. For example, you could write a filter that downgrades
- ``ERROR`` log records to ``WARNING`` records if a particular set of
- criteria are met.
- Filters can be installed on loggers or on handlers; multiple filters
- can be used in a chain to perform multiple filtering actions.
- .. _topic-logging-parts-formatters:
- Formatters
- ~~~~~~~~~~
- Ultimately, a log record needs to be rendered as text. *Formatters*
- describe the exact format of that text. A formatter usually consists
- 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-security-implications:
- Security implications
- =====================
- 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:
- * what information is collected
- * where it will subsequently be stored
- * how it will be transferred
- * who might have access to it.
- 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>`.
- ``AdminEmailHandler``
- ---------------------
- 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
- 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:
- Configuring logging
- ===================
- Python's logging library provides several techniques to configure
- logging, ranging from a programmatic interface to configuration files.
- By default, Django uses the :ref:`dictConfig format
- <logging-config-dictschema>`.
- In order to configure logging, you use :setting:`LOGGING` to define a
- dictionary of logging settings. These settings describe the loggers,
- handlers, filters and formatters that you want in your logging setup,
- and the log levels and other properties that you want those components
- to have.
- By default, the :setting:`LOGGING` setting is merged with :ref:`Django's
- default logging configuration <default-logging-configuration>` using the
- following scheme.
- If the ``disable_existing_loggers`` key in the :setting:`LOGGING` dictConfig is
- set to ``True`` (which is the ``dictConfig`` default if the key is missing)
- then all loggers from the default configuration will be disabled. Disabled
- loggers are not the same as removed; the logger will still exist, but will
- silently discard anything logged to it, not even propagating entries to a
- parent logger. Thus you should be very careful using
- ``'disable_existing_loggers': True``; it's probably not what you want. Instead,
- you can set ``disable_existing_loggers`` to ``False`` and redefine some or all
- of the default loggers; or you can set :setting:`LOGGING_CONFIG` to ``None``
- and :ref:`handle logging config yourself <disabling-logging-configuration>`.
- Logging is configured as part of the general Django ``setup()`` function.
- Therefore, you can be certain that loggers are always ready for use in your
- project code.
- Examples
- --------
- The full documentation for :ref:`dictConfig format <logging-config-dictschema>`
- is the best source of information about logging configuration dictionaries.
- However, to give you a taste of what is possible, here are several examples.
- To begin, here's a small configuration that will allow you to output all log
- messages to the console:
- .. code-block:: python
- :caption: ``settings.py``
- import os
- LOGGING = {
- "version": 1,
- "disable_existing_loggers": False,
- "handlers": {
- "console": {
- "class": "logging.StreamHandler",
- },
- },
- "root": {
- "handlers": ["console"],
- "level": "WARNING",
- },
- }
- This configures the parent ``root`` logger to send messages with the
- ``WARNING`` level and higher to the console handler. By adjusting the level to
- ``INFO`` or ``DEBUG`` you can display more messages. This may be useful during
- development.
- Next we can add more fine-grained logging. Here's an example of how to make the
- logging system print more messages from just the :ref:`django-logger` named
- logger:
- .. code-block:: python
- :caption: ``settings.py``
- import os
- LOGGING = {
- "version": 1,
- "disable_existing_loggers": False,
- "handlers": {
- "console": {
- "class": "logging.StreamHandler",
- },
- },
- "root": {
- "handlers": ["console"],
- "level": "WARNING",
- },
- "loggers": {
- "django": {
- "handlers": ["console"],
- "level": os.getenv("DJANGO_LOG_LEVEL", "INFO"),
- "propagate": False,
- },
- },
- }
- By default, this config sends messages from the ``django`` logger of level
- ``INFO`` or higher to the console. This is the same level as Django's default
- logging config, except that the default config only displays log records when
- ``DEBUG=True``. Django does not log many such ``INFO`` level messages. With
- this config, however, you can also set the environment variable
- ``DJANGO_LOG_LEVEL=DEBUG`` to see all of Django's debug logging which is very
- verbose as it includes all database queries.
- You don't have to log to the console. Here's a configuration which writes all
- logging from the :ref:`django-logger` named logger to a local file:
- .. code-block:: python
- :caption: ``settings.py``
- LOGGING = {
- "version": 1,
- "disable_existing_loggers": False,
- "handlers": {
- "file": {
- "level": "DEBUG",
- "class": "logging.FileHandler",
- "filename": "/path/to/django/debug.log",
- },
- },
- "loggers": {
- "django": {
- "handlers": ["file"],
- "level": "DEBUG",
- "propagate": True,
- },
- },
- }
- If you use this example, be sure to change the ``'filename'`` path to a
- location that's writable by the user that's running the Django application.
- Finally, here's an example of a fairly complex logging setup:
- .. code-block:: python
- :caption: ``settings.py``
- LOGGING = {
- "version": 1,
- "disable_existing_loggers": False,
- "formatters": {
- "verbose": {
- "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
- "style": "{",
- },
- "simple": {
- "format": "{levelname} {message}",
- "style": "{",
- },
- },
- "filters": {
- "special": {
- "()": "project.logging.SpecialFilter",
- "foo": "bar",
- },
- "require_debug_true": {
- "()": "django.utils.log.RequireDebugTrue",
- },
- },
- "handlers": {
- "console": {
- "level": "INFO",
- "filters": ["require_debug_true"],
- "class": "logging.StreamHandler",
- "formatter": "simple",
- },
- "mail_admins": {
- "level": "ERROR",
- "class": "django.utils.log.AdminEmailHandler",
- "filters": ["special"],
- },
- },
- "loggers": {
- "django": {
- "handlers": ["console"],
- "propagate": True,
- },
- "django.request": {
- "handlers": ["mail_admins"],
- "level": "ERROR",
- "propagate": False,
- },
- "myproject.custom": {
- "handlers": ["console", "mail_admins"],
- "level": "INFO",
- "filters": ["special"],
- },
- },
- }
- This logging configuration does the following things:
- * Identifies the configuration as being in 'dictConfig version 1'
- format. At present, this is the only dictConfig format version.
- * Defines two formatters:
- * ``simple``, that outputs the log level name (e.g., ``DEBUG``) and the log
- message.
- The ``format`` string is a normal Python formatting string
- describing the details that are to be output on each logging
- line. The full list of detail that can be output can be
- found in :ref:`formatter-objects`.
- * ``verbose``, that outputs the log level name, the log
- message, plus the time, process, thread and module that
- generate the log message.
- * Defines two filters:
- * ``project.logging.SpecialFilter``, using the alias ``special``. If this
- filter required additional arguments, they can be provided as additional
- keys in the filter configuration dictionary. In this case, the argument
- ``foo`` will be given a value of ``bar`` when instantiating
- ``SpecialFilter``.
- * ``django.utils.log.RequireDebugTrue``, which passes on records when
- :setting:`DEBUG` is ``True``.
- * Defines two handlers:
- * ``console``, a :class:`~logging.StreamHandler`, which prints any ``INFO``
- (or higher) message to ``sys.stderr``. This handler uses the ``simple``
- output format.
- * ``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:
- * ``django``, which passes all messages to the ``console`` handler.
- * ``django.request``, which passes all ``ERROR`` messages to
- the ``mail_admins`` handler. In addition, this logger is
- marked to *not* propagate messages. This means that log
- messages written to ``django.request`` will not be handled
- by the ``django`` logger.
- * ``myproject.custom``, which passes all messages at ``INFO``
- or higher that also pass the ``special`` filter to two
- handlers -- the ``console``, and ``mail_admins``. This
- means that all ``INFO`` level messages (or higher) will be
- printed to the console; ``ERROR`` and ``CRITICAL``
- messages will also be output via email.
- Custom logging configuration
- ----------------------------
- If you don't want to use Python's dictConfig format to configure your
- logger, you can specify your own configuration scheme.
- The :setting:`LOGGING_CONFIG` setting defines the callable that will
- be used to configure Django's loggers. By default, it points at
- Python's :func:`logging.config.dictConfig()` function. However, if you want to
- use a different configuration process, you can use any other callable
- that takes a single argument. The contents of :setting:`LOGGING` will
- be provided as the value of that argument when logging is configured.
- .. _disabling-logging-configuration:
- Disabling logging configuration
- -------------------------------
- If you don't want to configure logging at all (or you want to manually
- configure logging using your own approach), you can set
- :setting:`LOGGING_CONFIG` to ``None``. This will disable the
- configuration process for :ref:`Django's default logging
- <default-logging-configuration>`.
- Setting :setting:`LOGGING_CONFIG` to ``None`` only means that the automatic
- configuration process is disabled, not logging itself. If you disable the
- configuration process, Django will still make logging calls, falling back to
- whatever default logging behavior is defined.
- Here's an example that disables Django's logging configuration and then
- manually configures logging:
- .. code-block:: python
- :caption: ``settings.py``
- LOGGING_CONFIG = None
- import logging.config
- logging.config.dictConfig(...)
- Note that the default configuration process only calls
- :setting:`LOGGING_CONFIG` once settings are fully-loaded. In contrast, manually
- 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.
|