Skip to content

Commit

Permalink
[docs] Update logging cookbook with recipe for using a logger like an…
Browse files Browse the repository at this point in the history
… output… (pythonGH-97730)
  • Loading branch information
vsajip authored and serhiy-storchaka committed Oct 2, 2022
1 parent 299dd41 commit 551b707
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions Doc/howto/logging-cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this::
i = 1
logger.debug('Message %d', i, extra=extra)

How to treat a logger like an output stream
-------------------------------------------

Sometimes, you need to interface to a third-party API which expects a file-like
object to write to, but you want to direct the API's output to a logger. You
can do this using a class which wraps a logger with a file-like API.
Here's a short script illustrating such a class:

.. code-block:: python
import logging
class LoggerWriter:
def __init__(self, logger, level):
self.logger = logger
self.level = level
def write(self, message):
if message != '\n': # avoid printing bare newlines, if you like
self.logger.log(self.level, message)
def flush(self):
# doesn't actually do anything, but might be expected of a file-like
# object - so optional depending on your situation
pass
def close(self):
# doesn't actually do anything, but might be expected of a file-like
# object - so optional depending on your situation. You might want
# to set a flag so that later calls to write raise an exception
pass
def main():
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('demo')
info_fp = LoggerWriter(logger, logging.INFO)
debug_fp = LoggerWriter(logger, logging.DEBUG)
print('An INFO message', file=info_fp)
print('A DEBUG message', file=debug_fp)
if __name__ == "__main__":
main()
When this script is run, it prints

.. code-block:: text
INFO:demo:An INFO message
DEBUG:demo:A DEBUG message
You could also use ``LoggerWriter`` to redirect ``sys.stdout`` and
``sys.stderr`` by doing something like this:

.. code-block:: python
import sys
sys.stdout = LoggerWriter(logger, logging.INFO)
sys.stderr = LoggerWriter(logger, logging.WARNING)
You should do this *after* configuring logging for your needs. In the above
example, the :func:`~logging.basicConfig` call does this (using the
``sys.stderr`` value *before* it is overwritten by a ``LoggerWriter``
instance). Then, you'd get this kind of result:

.. code-block:: pycon
>>> print('Foo')
INFO:demo:Foo
>>> print('Bar', file=sys.stderr)
WARNING:demo:Bar
>>>
Of course, these above examples show output according to the format used by
:func:`~logging.basicConfig`, but you can use a different formatter when you
configure logging.

.. patterns-to-avoid:
Expand Down

0 comments on commit 551b707

Please sign in to comment.