profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/evildmp/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
Daniele Procida evildmp Cardiff, Wales Creator of Diátaxis and BrachioGraph. Django core developer. Fellow of the Python Software Foundation.

evildmp/BrachioGraph 514

BrachioGraph is an ultra-cheap (total cost of materials: €14) plotter that can be built with minimal skills.

evildmp/C-is-for-Camera 148

A 35mm camera, based on the Canonet G-III QL17 rangefinder, modelled in Python.

evildmp/Arkestra 140

Arkestra extends Django CMS to provide an intelligent semantic web publishing system for organisations and institutions.

evildmp/diataxis-documentation-framework 139

"The Grand Unified Theory of Documentation" (David Laing) - a popular and transformative documentation authoring framework

evildmp/afraid-to-commit 99

Don't be afraid to commit - a workshop/tutorial for inexperienced Python/Django developers who would like to contribute more to the projects they use.

evildmp/DjangoConEuropeTranscripts 12

Proceedings from DjangoCon Europe 2015

evildmp/django-inspector 10

Inspects and reports on Django sites

evildmp/conference-handbook 9

Handbook for open-source software community conference organisers

pull request commentdjango/django

Refs #32880 -- Retitled some how-to documents.

@felixxm Yes, will do. I'll do that in the next PR, unless it's important for them all to be done together.

evildmp

comment created time in 12 days

Pull request review commentdjango/django

Refs #32880 -- Retitled some how-to documents.

-==============-Custom Lookups-==============+===========================+How to write custom Lookups

Agreed on both your suggestions, thanks.

evildmp

comment created time in 12 days

PullRequestReviewEvent

push eventevildmp/django

Daniele Procida

commit sha 39ccac519506bced1f45df92fd785afc2a3f80ba

Refs #32880 -- Retitled some how-to documents. Retitled documents for consistency, since some already (correctly) begin "How to...".

view details

push time in 12 days

PR opened django/django

Refs #32880 -- Retitled some how-to documents.

Retitled documents for consistency, since some already (correctly) begin "How to...".

+45 -45

0 comment

15 changed files

pr created time in 12 days

push eventevildmp/django

Daniele Procida

commit sha 292914328b24e9fe2409aabf056eb42a8dfa2bf4

Refs #32880 -- Retitled some how-to documents. Retitled documents for consistency, since some already (correctly) begin "How to...".

view details

push time in 12 days

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to document.

 Django's logging module extends Python's builtin :mod:`logging`. Logging is configured as part of the general Django :func:`django.setup` function, so it's always available unless explicitly disabled. -.. _default-logging-configuration:+.. _logging-default-configuration:

+1

evildmp

comment created time in 13 days

PullRequestReviewEvent

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

 Django's logging module extends Python's builtin :mod:`logging`. Logging is configured as part of the general Django :func:`django.setup` function, so it's always available unless explicitly disabled. -.. _default-logging-configuration:+.. _logging-default-configuration:

Sorry, I thought I had reverted it. It should be default-logging-configuration. I can push that now, but it's not clear to me if you pushed something else in commit bf71942 that will be overwritten.

evildmp

comment created time in 13 days

PullRequestReviewEvent

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

+.. _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+<logging-default-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__)++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')++Note that log records with a level lower than ``WARNING`` won't appear in the+console by default.++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 <logging-default-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+---------------------------++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 configures+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',+        },+    },

In the end I couldn't really find a better solution.

  • defining them all in order of dependency means defining the rather inessential formatters first
  • defining them in logger > handler > formatter order would be conceptually better, but would mean cutting back twice instead of once (this would be my second-best choice compromise.
evildmp

comment created time in 15 days

PullRequestReviewEvent

push eventevildmp/django

Daniele Procida

commit sha c4fcd255ae667e05524f5f56fe7523f380ad59ab

Refs #32880 -- Created a new logging how-to section Moved how-to material from topic document into a new document, and added new material. Introduced minor improvements to logging reference document.

view details

push time in 15 days

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

+.. _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+<logging-default-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__)++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')++Note that log records with a level lower than ``WARNING`` won't appear in the+console by default.++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 <logging-default-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+---------------------------++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 configures+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 QA 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

Yes, it needs to be escaped otherwise the - is interpreted as list item.

(Or are you are questioning the -? I feel that's appropriate there, to introduce a clear pause in the sentence between the action and the reason for it.)

evildmp

comment created time in 15 days

PullRequestReviewEvent

push eventevildmp/diataxis-documentation-framework

Daniele Procida

commit sha 370d8ec7290d0a11b18e7040753cbb4917606066

Fixed a typo, made a small change

view details

push time in 17 days

push eventevildmp/diataxis-documentation-framework

Cynthia Peter

commit sha f8cf811780db12dd3cf08eeb46961f652b90996c

Deleted a repeated word

view details

Daniele Procida

commit sha e241aca32615cc503dc6d98a3342685fac07442c

Merge pull request #40 from CynthiaPeter/bugfix-repeated-text Deleted a repeated word

view details

push time in 17 days

push eventevildmp/diataxis-documentation-framework

Matt Cone

commit sha 3358cbc4fb9f1387d8a5f713853ff55d866786cc

Delete duplicate word

view details

Daniele Procida

commit sha c39c137398f6a2ebb48ab2555ee00ab6cc11de69

Merge pull request #38 from mattcone/patch-1 Delete duplicate word

view details

push time in 17 days

PR merged evildmp/diataxis-documentation-framework

Delete duplicate word

Thanks for creating this resource! I'm proposing a small edit to remove a duplicated word.

+1 -1

3 comments

1 changed file

mattcone

pr closed time in 17 days

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

+.. _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+<logging-default-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__)++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')++Note that log records with a level lower than ``WARNING`` won't appear in the+console by default.++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 <logging-default-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+---------------------------++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 configures+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',+        },+    },

This dilemma is exactly why the guide tackles them in that order. I don't think there is a really elegant solution but I will have another look.

evildmp

comment created time in 19 days

PullRequestReviewEvent

push eventevildmp/django

Daniele Procida

commit sha 5c12f61482040932d6eefef4f31c2087d735298d

Refs #32880 -- Created a new logging how-to section Moved how-to material from topic document into a new document, and added new material. Introduced minor improvements to logging reference document.

view details

push time in 19 days

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

+.. _logging-how-to:++================================+How to configure and use logging

@tim-mccurrach Yes, you're one step ahead of me. A how-to guide should indicate in its title just what you will be shown how to do, so you can see whether your needs are likely to be answered in it.

evildmp

comment created time in 20 days

PullRequestReviewEvent

push eventevildmp/django

Daniele Procida

commit sha 902596cfd23d1afc929ea747e914b6d9198aa717

Refs #32880 -- Created a new logging how-to section Moved how-to material from topic document into a new document, and added new material. Introduced minor improvements to logging reference document.

view details

push time in 21 days

Pull request review commentdjango/django

Refs #32880 -- Created a new logging how-to section

+.. _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+<logging-default-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`. The ``getLogger()`` method must be provided+with a name. It's this name that is used to identify a logger 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__)++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')++Note that log records with a level lower than ``WARNING`` won't appear in the+console by default.++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 <logging-default-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+---------------------------++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 define your formatters, for example:++..  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, configure the handler, 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.++A mapping named ``django`` would only process records from logger instances in+the ``django`` namespace. A mapping named ``django.contrib`` would be even more+restrictive.++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`` will capture records from this logger, but+ignore those from (say) the ``django`` namespace:++..  code-block:: python+    :emphasize-lines: 4++    LOGGING = {+        [...]+        'loggers': {+            'my_app': {+                ...+            },+        },+    }++A logger mapping named ``my_app.views`` will only capture records from that+module:

Thanks for catching this one, I have been trying to move away from the language of modules to talk instead about the loggers' namespaces.

evildmp

comment created time in 21 days

PullRequestReviewEvent

pull request commentdjango/django

Refs #32880 -- Created a new logging how-to section

@felixxm @carltongibson I have a few questions about this, and it might be more efficient to discuss them in a call if you prefer, once you've had a brief look at this but before you spend time in detailed review.

evildmp

comment created time in 21 days

PR opened django/django

Refs #32880 -- Created a new logging how-to section

Moved how-to material from topic document into a new document, and added new material. Introduced minor improvements to logging reference document.

+362 -105

0 comment

4 changed files

pr created time in 21 days