mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Moved how-to material from topic document into a new document, and added new material. Introduced minor improvements to logging reference document.
		
			
				
	
	
		
			344 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| .. _logging-how-to:
 | |
| 
 | |
| ================================
 | |
| How to configure and use logging
 | |
| ================================
 | |
| 
 | |
| .. seealso::
 | |
| 
 | |
|     * :ref:`Django logging reference <logging-ref>`
 | |
|     * :ref:`Django logging overview <logging-explanation>`
 | |
| 
 | |
| Django provides a working :ref:`default logging configuration
 | |
| <default-logging-configuration>` that is readily extended.
 | |
| 
 | |
| Make a basic logging call
 | |
| =========================
 | |
| 
 | |
| 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`. Provide the ``getLogger()`` method with a
 | |
| name to identify it and the records it emits. A good option is to use
 | |
| ``__name__`` (see :ref:`naming-loggers` below for more on this) which will
 | |
| provide the name of the current Python module as a dotted path::
 | |
| 
 | |
|     import logging
 | |
| 
 | |
|     logger = logging.getLogger(__name__)
 | |
| 
 | |
| It's a good convention to perform this declaration at module level.
 | |
| 
 | |
| And then in a function, for example in a view, send a record to the logger::
 | |
| 
 | |
|     def some_view(request):
 | |
|         ...
 | |
|         if some_risky_state:
 | |
|             logger.warning('Platform is running at risk')
 | |
| 
 | |
| When this code is executed, a :py:class:`~logging.LogRecord` containing that
 | |
| message will be sent to the logger. If you're using Django's default logging
 | |
| configuration, the message 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')
 | |
| 
 | |
| .. important::
 | |
| 
 | |
|     Records with a level lower than ``WARNING`` will not appear in the console
 | |
|     by default. Changing this behavior requires additional configuration.
 | |
| 
 | |
| Customize logging configuration
 | |
| ===============================
 | |
| 
 | |
| Although Django's logging configuration works out of the box, you can control
 | |
| exactly how your logs are sent to various destinations - to log files, external
 | |
| services, email and so on - with some additional configuration.
 | |
| 
 | |
| You can configure:
 | |
| 
 | |
| * logger mappings, to determine which records are sent to which handlers
 | |
| * handlers, to determine what they do with the records they receive
 | |
| * filters, to provide additional control over the transfer of records, and
 | |
|   even modify records in-place
 | |
| * formatters, to convert :class:`~logging.LogRecord` objects to a string or
 | |
|   other form for consumption by human beings or another system
 | |
| 
 | |
| There are various ways of configuring logging. In Django, the
 | |
| :setting:`LOGGING` setting is most commonly used. The setting uses the
 | |
| :ref:`dictConfig format <logging-config-dictschema>`, and extends the
 | |
| :ref:`default logging configuration <default-logging-definition>`.
 | |
| 
 | |
| See :ref:`configuring-logging` for an explanation of how your custom settings
 | |
| are merged with Django's defaults.
 | |
| 
 | |
| See the :mod:`Python logging documentation <python:logging.config>` for
 | |
| details of other ways of configuring logging. For the sake of simplicity, this
 | |
| documentation will only consider configuration via the ``LOGGING`` setting.
 | |
| 
 | |
| .. _basic-logger-configuration:
 | |
| 
 | |
| Basic logging configuration
 | |
| ---------------------------
 | |
| 
 | |
| When configuring logging, it makes sense to
 | |
| 
 | |
| Create a ``LOGGING`` dictionary
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| In your ``settings.py``::
 | |
| 
 | |
|     LOGGING = {
 | |
|         'version': 1,                       # the dictConfig format version
 | |
|         'disable_existing_loggers': False,  # retain the default loggers
 | |
|     }
 | |
| 
 | |
| It nearly always makes sense to retain and extend the default logging
 | |
| configuration by setting ``disable_existing_loggers`` to ``False``.
 | |
| 
 | |
| Configure a handler
 | |
| ~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| This example configures a single handler named ``file``, that uses Python's
 | |
| :class:`~logging.FileHandler` to save logs of level ``DEBUG`` and higher to the
 | |
| file ``general.log`` (at the project root):
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 3-8
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'handlers': {
 | |
|             'file': {
 | |
|                 'class': 'logging.FileHandler',
 | |
|                 'filename': 'general.log',
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| Different handler classes take different configuration options. For more
 | |
| information on available handler classes, see the
 | |
| :class:`~django.utils.log.AdminEmailHandler` provided by Django and the various
 | |
| :py:mod:`handler classes <logging.handlers>` provided by Python.
 | |
| 
 | |
| Logging levels can also be set on the handlers (by default, they accept log
 | |
| messages of all levels). Using the example above, adding:
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 4
 | |
| 
 | |
|     {
 | |
|         'class': 'logging.FileHandler',
 | |
|         'filename': 'general.log',
 | |
|         'level': 'DEBUG',
 | |
|     }
 | |
| 
 | |
| would define a handler configuration that only accepts records of level
 | |
| ``DEBUG`` and higher.
 | |
| 
 | |
| Configure a logger mapping
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| To send records to this handler, configure a logger mapping to use it for
 | |
| example:
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 3-8
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'loggers': {
 | |
|             '': {
 | |
|                 'level': 'DEBUG',
 | |
|                 'handlers': ['file'],
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| The mapping's name determines which log records it will process. This
 | |
| configuration (``''``) is *unnamed*. That means that it will process records
 | |
| from *all* loggers (see :ref:`naming-loggers` below on how to use the mapping
 | |
| name to determine the loggers for which it will process records).
 | |
| 
 | |
| It will forward messages of levels ``DEBUG`` and higher to the handler named
 | |
| ``file``.
 | |
| 
 | |
| Note that a logger can forward messages to multiple handlers, so the relation
 | |
| between loggers and handlers is many-to-many.
 | |
| 
 | |
| If you execute::
 | |
| 
 | |
|     logger.debug('Attempting to connect to API')
 | |
| 
 | |
| in your code, you will find that message in the file ``general.log`` in the
 | |
| root of the project.
 | |
| 
 | |
| Configure a formatter
 | |
| ~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| By default, the final log output contains the message part of each :class:`log
 | |
| record <logging.LogRecord>`. Use a formatter if you want to include additional
 | |
| data. First name and define your formatters - this example defines
 | |
| formatters named ``verbose`` and ``simple``:
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 3-12
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'formatters': {
 | |
|             'verbose': {
 | |
|                 'format': '{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}',
 | |
|                 'style': '{',
 | |
|             },
 | |
|             'simple': {
 | |
|                 'format': '{levelname} {message}',
 | |
|                 'style': '{',
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| The ``style`` keyword allows you to specify ``{`` for :meth:`str.format` or
 | |
| ``$`` for :class:`string.Template` formatting; the default is ``$``.
 | |
| 
 | |
| See :ref:`logrecord-attributes` for the :class:`~logging.LogRecord` attributes
 | |
| you can include.
 | |
| 
 | |
| To apply a formatter to a handler, add a ``formatter`` entry to the handler's
 | |
| dictionary referring to the formatter by name, for example:
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 5
 | |
| 
 | |
|     'handlers': {
 | |
|         'file': {
 | |
|             'class': 'logging.FileHandler',
 | |
|             'filename': 'general.log',
 | |
|             'formatter': 'verbose',
 | |
|         },
 | |
|     },
 | |
| 
 | |
| .. _naming-loggers:
 | |
| 
 | |
| Use logger namespacing
 | |
| ~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| The unnamed logging configuration ``''`` captures logs from any Python
 | |
| application. A named logging configuration will capture logs only from loggers
 | |
| with matching names.
 | |
| 
 | |
| The namespace of a logger instance is defined using
 | |
| :py:func:`~logging.getLogger`. For example in ``views.py`` of ``my_app``::
 | |
| 
 | |
|     logger = logging.getLogger(__name__)
 | |
| 
 | |
| will create a logger in the ``my_app.views`` namespace. ``__name__`` allows you
 | |
| to organize log messages according to their provenance within your project's
 | |
| applications automatically. It also ensures that you will not experience name
 | |
| collisions.
 | |
| 
 | |
| A logger mapping named ``my_app.views`` will capture records from this logger:
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 4
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'loggers': {
 | |
|             'my_app.views': {
 | |
|                 ...
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| A logger mapping named ``my_app`` will be more permissive, capturing records
 | |
| from loggers anywhere within the ``my_app`` namespace (including
 | |
| ``my_app.views``, ``my_app.utils``, and so on):
 | |
| 
 | |
| .. code-block:: python
 | |
|     :emphasize-lines: 4
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'loggers': {
 | |
|             'my_app': {
 | |
|                 ...
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| You can also define logger namespacing explicitly::
 | |
| 
 | |
|     logger = logging.getLogger('project.payment')
 | |
| 
 | |
| and set up logger mappings accordingly.
 | |
| 
 | |
| .. _naming-loggers-hierarchy:
 | |
| 
 | |
| Using logger hierarchies and propagation
 | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
| 
 | |
| Logger naming is *hierarchical*. ``my_app`` is the parent of ``my_app.views``,
 | |
| which is the parent of ``my_app.views.private``. Unless specified otherwise,
 | |
| logger mappings will propagate the records they process to their parents - a
 | |
| record from a logger in the ``my_app.views.private`` namespace will be handled
 | |
| by a mapping for both ``my_app`` and ``my_app.views``.
 | |
| 
 | |
| To manage this behavior, set the propagation key on the mappings you define::
 | |
| 
 | |
|     LOGGING = {
 | |
|         [...]
 | |
|         'loggers': {
 | |
|             'my_app': {
 | |
|                 [...]
 | |
|             },
 | |
|             'my_app.views': {
 | |
|                 [...]
 | |
|             },
 | |
|             'my_app.views.private': {
 | |
|                 [...]
 | |
|                 'propagate': False,
 | |
|             },
 | |
|         },
 | |
|     }
 | |
| 
 | |
| ``propagate`` defaults to ``True``. In this example, the logs from
 | |
| ``my_app.views.private`` will not be handled by the parent, but logs from
 | |
| ``my_app.views`` will.
 | |
| 
 | |
| Configure responsive logging
 | |
| ----------------------------
 | |
| 
 | |
| Logging is most useful when it contains as much information as possible, but
 | |
| not information that you don't need - and how much you need depends upon what
 | |
| you're doing. When you're debugging, you need a level of information that would
 | |
| be excessive and unhelpful if you had to deal with it in production.
 | |
| 
 | |
| You can configure logging to provide you with the level of detail you need,
 | |
| when you need it. Rather than manually change configuration to achieve this, a
 | |
| better way is to apply configuration automatically according to the
 | |
| environment.
 | |
| 
 | |
| For example, you could set an environment variable ``DJANGO_LOG_LEVEL``
 | |
| appropriately in your development and staging environments, and make use of it
 | |
| in a logger mapping thus::
 | |
| 
 | |
|     'level': os.getenv('DJANGO_LOG_LEVEL', 'WARNING')
 | |
| 
 | |
| \- so that unless the environment specifies a lower log level, this
 | |
| configuration will only forward records of severity ``WARNING`` and above to
 | |
| its handler.
 | |
| 
 | |
| Other options in the configuration (such as the ``level`` or ``formatter``
 | |
| option of handlers) can be similarly managed.
 |