.. _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 asexpected, because *logging will not be set up at that point*. To explorelogging, use a view function as suggested in the example below.First, import the Python logging library, and then obtain a logger instancewith :py:func:`logging.getLogger`. Provide the ``getLogger()`` method with aname 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 willprovide the name of the current Python module as a dotted path::import logginglogger = 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 thatmessage will be sent to the logger. If you're using Django's default loggingconfiguration, 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 consoleby default. Changing this behavior requires additional configuration.Customize logging configuration===============================Although Django's logging configuration works out of the box, you can controlexactly how your logs are sent to various destinations - to log files, externalservices, 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, andeven modify records in-place* formatters, to convert :class:`~logging.LogRecord` objects to a string orother form for consumption by human beings or another systemThere 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 settingsare merged with Django's defaults.See the :mod:`Python logging documentation <python:logging.config>` fordetails of other ways of configuring logging. For the sake of simplicity, thisdocumentation will only consider configuration via the ``LOGGING`` setting... _basic-logger-configuration:Basic logging configuration---------------------------When configuring logging, it makes sense toCreate 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 loggingconfiguration 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 thefile ``general.log`` (at the project root):.. code-block:: python:emphasize-lines: 3-8LOGGING = {[...]'handlers': {'file': {'class': 'logging.FileHandler','filename': 'general.log',},},}Different handler classes take different configuration options. For moreinformation 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 logmessages 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 forexample:.. code-block:: python:emphasize-lines: 3-8LOGGING = {[...]'loggers': {'': {'level': 'DEBUG','handlers': ['file'],},},}The mapping's name determines which log records it will process. Thisconfiguration (``''``) is *unnamed*. That means that it will process recordsfrom *all* loggers (see :ref:`naming-loggers` below on how to use the mappingname 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 relationbetween 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 theroot of the project.Configure a formatter~~~~~~~~~~~~~~~~~~~~~By default, the final log output contains the message part of each :class:`logrecord <logging.LogRecord>`. Use a formatter if you want to include additionaldata. First name and define your formatters - this example definesformatters named ``verbose`` and ``simple``:.. code-block:: python:emphasize-lines: 3-12LOGGING = {[...]'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` attributesyou can include.To apply a formatter to a handler, add a ``formatter`` entry to the handler'sdictionary 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 Pythonapplication. A named logging configuration will capture logs only from loggerswith 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 youto organize log messages according to their provenance within your project'sapplications automatically. It also ensures that you will not experience namecollisions.A logger mapping named ``my_app.views`` will capture records from this logger:.. code-block:: python:emphasize-lines: 4LOGGING = {[...]'loggers': {'my_app.views': {...},},}A logger mapping named ``my_app`` will be more permissive, capturing recordsfrom loggers anywhere within the ``my_app`` namespace (including``my_app.views``, ``my_app.utils``, and so on):.. code-block:: python:emphasize-lines: 4LOGGING = {[...]'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 - arecord from a logger in the ``my_app.views.private`` namespace will be handledby 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, butnot information that you don't need - and how much you need depends upon whatyou're doing. When you're debugging, you need a level of information that wouldbe 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, abetter way is to apply configuration automatically according to theenvironment.For example, you could set an environment variable ``DJANGO_LOG_LEVEL``appropriately in your development and staging environments, and make use of itin a logger mapping thus::'level': os.getenv('DJANGO_LOG_LEVEL', 'WARNING')\- so that unless the environment specifies a lower log level, thisconfiguration will only forward records of severity ``WARNING`` and above toits handler.Other options in the configuration (such as the ``level`` or ``formatter``option of handlers) can be similarly managed.