mirror of
https://github.com/python/cpython.git
synced 2025-08-16 23:01:34 +00:00
[3.11] [docs] Update logging cookbook with recipe for using a logger like an output… (GH-97730) (GH-97735)
This commit is contained in:
parent
8c528ef4a1
commit
011260bca0
1 changed files with 76 additions and 0 deletions
|
@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this::
|
||||||
i = 1
|
i = 1
|
||||||
logger.debug('Message %d', i, extra=extra)
|
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:
|
.. patterns-to-avoid:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue