Skip to content

Commit

Permalink
[doc] Improve logging cookbook example. (GH-98481)
Browse files Browse the repository at this point in the history
  • Loading branch information
vsajip authored Oct 20, 2022
1 parent ff173ed commit a956c2f
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions Doc/howto/logging-cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3712,6 +3712,71 @@ Of course, the examples above show output according to the format used by
:func:`~logging.basicConfig`, but you can use a different formatter when you
configure logging.

Note that with the above scheme, you are somewhat at the mercy of buffering and
the sequence of write calls which you are intercepting. For example, with the
definition of ``LoggerWriter`` above, if you have the snippet

.. code-block:: python
sys.stderr = LoggerWriter(logger, logging.WARNING)
1 / 0
then running the script results in

.. code-block:: text
WARNING:demo:Traceback (most recent call last):
WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 53, in <module>
WARNING:demo:
WARNING:demo:main()
WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 49, in main
WARNING:demo:
WARNING:demo:1 / 0
WARNING:demo:ZeroDivisionError
WARNING:demo::
WARNING:demo:division by zero
As you can see, this output isn't ideal. That's because the underlying code
which writes to ``sys.stderr`` makes mutiple writes, each of which results in a
separate logged line (for example, the last three lines above). To get around
this problem, you need to buffer things and only output log lines when newlines
are seen. Let's use a slghtly better implementation of ``LoggerWriter``:

.. code-block:: python
class BufferingLoggerWriter(LoggerWriter):
def __init__(self, logger, level):
super().__init__(logger, level)
self.buffer = ''
def write(self, message):
if '\n' not in message:
self.buffer += message
else:
parts = message.split('\n')
if self.buffer:
s = self.buffer + parts.pop(0)
self.logger.log(self.level, s)
self.buffer = parts.pop()
for part in parts:
self.logger.log(self.level, part)
This just buffers up stuff until a newline is seen, and then logs complete
lines. With this approach, you get better output:

.. code-block:: text
WARNING:demo:Traceback (most recent call last):
WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 55, in <module>
WARNING:demo: main()
WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 52, in main
WARNING:demo: 1/0
WARNING:demo:ZeroDivisionError: division by zero
.. patterns-to-avoid:
Patterns to avoid
Expand Down

0 comments on commit a956c2f

Please sign in to comment.