[doc] Update logging documentation to improve grammar and elucidate an example. (GH-117541)

This commit is contained in:
Vinay Sajip 2024-04-04 13:14:44 +01:00 committed by GitHub
parent b32789ccb9
commit df912c913a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 11 deletions

View file

@ -1915,7 +1915,7 @@ In a similar way to the above section, we can implement a listener and handler
using `pynng <https://pypi.org/project/pynng/>`_, which is a Python binding to
`NNG <https://nng.nanomsg.org/>`_, billed as a spiritual successor to ZeroMQ.
The following snippets illustrate -- you can test them in an environment which has
``pynng`` installed. Juat for variety, we present the listener first.
``pynng`` installed. Just for variety, we present the listener first.
Subclass ``QueueListener``
@ -1923,6 +1923,7 @@ Subclass ``QueueListener``
.. code-block:: python
# listener.py
import json
import logging
import logging.handlers
@ -1955,7 +1956,7 @@ Subclass ``QueueListener``
break
except pynng.Timeout:
pass
except pynng.Closed: # sometimes hit when you hit Ctrl-C
except pynng.Closed: # sometimes happens when you hit Ctrl-C
break
if data is None:
return None
@ -1988,6 +1989,7 @@ Subclass ``QueueHandler``
.. code-block:: python
# sender.py
import json
import logging
import logging.handlers
@ -2015,9 +2017,10 @@ Subclass ``QueueHandler``
logging.getLogger('pynng').propagate = False
handler = NNGSocketHandler(DEFAULT_ADDR)
# Make sure the process ID is in the output
logging.basicConfig(level=logging.DEBUG,
handlers=[logging.StreamHandler(), handler],
format='%(levelname)-8s %(name)10s %(message)s')
format='%(levelname)-8s %(name)10s %(process)6s %(message)s')
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,
logging.CRITICAL)
logger_names = ('myapp', 'myapp.lib1', 'myapp.lib2')
@ -2031,7 +2034,64 @@ Subclass ``QueueHandler``
delay = random.random() * 2 + 0.5
time.sleep(delay)
You can run the above two snippets in separate command shells.
You can run the above two snippets in separate command shells. If we run the
listener in one shell and run the sender in two separate shells, we should see
something like the following. In the first sender shell:
.. code-block:: console
$ python sender.py
DEBUG myapp 613 Message no. 1
WARNING myapp.lib2 613 Message no. 2
CRITICAL myapp.lib2 613 Message no. 3
WARNING myapp.lib2 613 Message no. 4
CRITICAL myapp.lib1 613 Message no. 5
DEBUG myapp 613 Message no. 6
CRITICAL myapp.lib1 613 Message no. 7
INFO myapp.lib1 613 Message no. 8
(and so on)
In the second sender shell:
.. code-block:: console
$ python sender.py
INFO myapp.lib2 657 Message no. 1
CRITICAL myapp.lib2 657 Message no. 2
CRITICAL myapp 657 Message no. 3
CRITICAL myapp.lib1 657 Message no. 4
INFO myapp.lib1 657 Message no. 5
WARNING myapp.lib2 657 Message no. 6
CRITICAL myapp 657 Message no. 7
DEBUG myapp.lib1 657 Message no. 8
(and so on)
In the listener shell:
.. code-block:: console
$ python listener.py
Press Ctrl-C to stop.
DEBUG myapp 613 Message no. 1
WARNING myapp.lib2 613 Message no. 2
INFO myapp.lib2 657 Message no. 1
CRITICAL myapp.lib2 613 Message no. 3
CRITICAL myapp.lib2 657 Message no. 2
CRITICAL myapp 657 Message no. 3
WARNING myapp.lib2 613 Message no. 4
CRITICAL myapp.lib1 613 Message no. 5
CRITICAL myapp.lib1 657 Message no. 4
INFO myapp.lib1 657 Message no. 5
DEBUG myapp 613 Message no. 6
WARNING myapp.lib2 657 Message no. 6
CRITICAL myapp 657 Message no. 7
CRITICAL myapp.lib1 613 Message no. 7
INFO myapp.lib1 613 Message no. 8
DEBUG myapp.lib1 657 Message no. 8
(and so on)
As you can see, the logging from the two sender processes is interleaved in the
listener's output.
An example dictionary-based configuration

View file

@ -63,12 +63,13 @@ If you run *myapp.py*, you should see this in *myapp.log*:
INFO:mylib:Doing something
INFO:__main__:Finished
The key features of this idiomatic usage is that the majority of code is simply
The key feature of this idiomatic usage is that the majority of code is simply
creating a module level logger with ``getLogger(__name__)``, and using that
logger to do any needed logging. This is concise while allowing downstream code
fine grained control if needed. Logged messages to the module-level logger get
forwarded up to handlers of loggers in higher-level modules, all the way up to
the root logger; for this reason this approach is known as hierarchical logging.
logger to do any needed logging. This is concise, while allowing downstream
code fine-grained control if needed. Logged messages to the module-level logger
get forwarded to handlers of loggers in higher-level modules, all the way up to
the highest-level logger known as the root logger; this approach is known as
hierarchical logging.
For logging to be useful, it needs to be configured: setting the levels and
destinations for each logger, potentially changing how specific modules log,
@ -82,8 +83,8 @@ The module provides a lot of functionality and flexibility. If you are
unfamiliar with logging, the best way to get to grips with it is to view the
tutorials (**see the links above and on the right**).
The basic classes defined by the module, together with their functions, are
listed below.
The basic classes defined by the module, together with their attributes and
methods, are listed in the sections below.
* Loggers expose the interface that application code directly uses.
* Handlers send the log records (created by loggers) to the appropriate