@@ -3712,6 +3712,71 @@ Of course, the examples above show output according to the format used by
37123712:func: `~logging.basicConfig `, but you can use a different formatter when you
37133713configure logging.
37143714
3715+ Note that with the above scheme, you are somewhat at the mercy of buffering and
3716+ the sequence of write calls which you are intercepting. For example, with the
3717+ definition of ``LoggerWriter `` above, if you have the snippet
3718+
3719+ .. code-block :: python
3720+
3721+ sys.stderr = LoggerWriter(logger, logging.WARNING )
3722+ 1 / 0
3723+
3724+ then running the script results in
3725+
3726+ .. code-block :: text
3727+
3728+ WARNING:demo:Traceback (most recent call last):
3729+
3730+ WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 53, in <module>
3731+
3732+ WARNING:demo:
3733+ WARNING:demo:main()
3734+ WARNING:demo: File "/home/runner/cookbook-loggerwriter/test.py", line 49, in main
3735+
3736+ WARNING:demo:
3737+ WARNING:demo:1 / 0
3738+ WARNING:demo:ZeroDivisionError
3739+ WARNING:demo::
3740+ WARNING:demo:division by zero
3741+
3742+ As you can see, this output isn't ideal. That's because the underlying code
3743+ which writes to ``sys.stderr `` makes mutiple writes, each of which results in a
3744+ separate logged line (for example, the last three lines above). To get around
3745+ this problem, you need to buffer things and only output log lines when newlines
3746+ are seen. Let's use a slghtly better implementation of ``LoggerWriter ``:
3747+
3748+ .. code-block :: python
3749+
3750+ class BufferingLoggerWriter (LoggerWriter ):
3751+ def __init__ (self , logger , level ):
3752+ super ().__init__ (logger, level)
3753+ self .buffer = ' '
3754+
3755+ def write (self , message ):
3756+ if ' \n ' not in message:
3757+ self .buffer += message
3758+ else :
3759+ parts = message.split(' \n ' )
3760+ if self .buffer:
3761+ s = self .buffer + parts.pop(0 )
3762+ self .logger.log(self .level, s)
3763+ self .buffer = parts.pop()
3764+ for part in parts:
3765+ self .logger.log(self .level, part)
3766+
3767+ This just buffers up stuff until a newline is seen, and then logs complete
3768+ lines. With this approach, you get better output:
3769+
3770+ .. code-block :: text
3771+
3772+ WARNING:demo:Traceback (most recent call last):
3773+ WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 55, in <module>
3774+ WARNING:demo: main()
3775+ WARNING:demo: File "/home/runner/cookbook-loggerwriter/main.py", line 52, in main
3776+ WARNING:demo: 1/0
3777+ WARNING:demo:ZeroDivisionError: division by zero
3778+
3779+
37153780.. patterns-to-avoid:
37163781
37173782 Patterns to avoid
0 commit comments