@@ -3428,6 +3428,82 @@ the above handler, you'd pass structured data using something like this::
3428
3428
i = 1
3429
3429
logger.debug('Message %d', i, extra=extra)
3430
3430
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.
3431
3507
3432
3508
.. patterns-to-avoid:
3433
3509
0 commit comments