@@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this::
34283428 i = 1
34293429 logger.debug('Message %d', i, extra=extra)
34303430
3431+ How to treat a logger like an output stream
3432+ -------------------------------------------
3433+
3434+ Sometimes, you need to interface to a third-party API which expects a file-like
3435+ object to write to, but you want to direct the API's output to a logger. You
3436+ can do this using a class which wraps a logger with a file-like API.
3437+ Here's a short script illustrating such a class:
3438+
3439+ .. code-block :: python
3440+
3441+ import logging
3442+
3443+ class LoggerWriter :
3444+ def __init__ (self , logger , level ):
3445+ self .logger = logger
3446+ self .level = level
3447+
3448+ def write (self , message ):
3449+ if message != ' \n ' : # avoid printing bare newlines, if you like
3450+ self .logger.log(self .level, message)
3451+
3452+ def flush (self ):
3453+ # doesn't actually do anything, but might be expected of a file-like
3454+ # object - so optional depending on your situation
3455+ pass
3456+
3457+ def close (self ):
3458+ # doesn't actually do anything, but might be expected of a file-like
3459+ # object - so optional depending on your situation. You might want
3460+ # to set a flag so that later calls to write raise an exception
3461+ pass
3462+
3463+ def main ():
3464+ logging.basicConfig(level = logging.DEBUG )
3465+ logger = logging.getLogger(' demo' )
3466+ info_fp = LoggerWriter(logger, logging.INFO )
3467+ debug_fp = LoggerWriter(logger, logging.DEBUG )
3468+ print (' An INFO message' , file = info_fp)
3469+ print (' A DEBUG message' , file = debug_fp)
3470+
3471+ if __name__ == " __main__" :
3472+ main()
3473+
3474+ When this script is run, it prints
3475+
3476+ .. code-block :: text
3477+
3478+ INFO:demo:An INFO message
3479+ DEBUG:demo:A DEBUG message
3480+
3481+ You could also use ``LoggerWriter `` to redirect ``sys.stdout `` and
3482+ ``sys.stderr `` by doing something like this:
3483+
3484+ .. code-block :: python
3485+
3486+ import sys
3487+
3488+ sys.stdout = LoggerWriter(logger, logging.INFO )
3489+ sys.stderr = LoggerWriter(logger, logging.WARNING )
3490+
3491+ You should do this *after * configuring logging for your needs. In the above
3492+ example, the :func: `~logging.basicConfig ` call does this (using the
3493+ ``sys.stderr `` value *before * it is overwritten by a ``LoggerWriter ``
3494+ instance). Then, you'd get this kind of result:
3495+
3496+ .. code-block :: pycon
3497+
3498+ >>> print('Foo')
3499+ INFO:demo:Foo
3500+ >>> print('Bar', file=sys.stderr)
3501+ WARNING:demo:Bar
3502+ >>>
3503+
3504+ Of course, these above examples show output according to the format used by
3505+ :func: `~logging.basicConfig `, but you can use a different formatter when you
3506+ configure logging.
34313507
34323508.. patterns-to-avoid:
34333509
0 commit comments