8000 gh-94503: Update logging cookbook with an example of uniformly handli… · python/cpython@d05423a · GitHub
[go: up one dir, main page]

Skip to content

Commit d05423a

Browse files
authored
gh-94503: Update logging cookbook with an example of uniformly handling newlines in output. (GH-136217)
1 parent 3e849d7 commit d05423a

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

Doc/howto/logging-cookbook.rst

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4078,6 +4078,68 @@ lines. With this approach, you get better output:
40784078
WARNING:demo: 1/0
40794079
WARNING:demo:ZeroDivisionError: division by zero
40804080
4081+
How to uniformly handle newlines in logging output
4082+
--------------------------------------------------
4083+
4084+
Usually, messages that are logged (say to console or file) consist of a single
4085+
line of text. However, sometimes there is a need to handle messages with
4086+
multiple lines - whether because a logging format string contains newlines, or
4087+
logged data contains newlines. If you want to handle such messages uniformly, so
4088+
that each line in the logged message appears uniformly formatted as if it was
4089+
logged separately, you can do this using a handler mixin, as in the following
4090+
snippet:
4091+
4092+
.. code-block:: python
4093+
4094+
# Assume this is in a module mymixins.py
4095+
import copy
4096+
4097+
class MultilineMixin:
4098+
def emit(self, record):
4099+
s = record.getMessage()
4100+
if '\n' not in s:
4101+
super().emit(record)
4102+
else:
4103+
lines = s.splitlines()
4104+
rec = copy.copy(record)
4105+
rec.args = None
4106+
for line in lines:
4107+
rec.msg = line
4108+
super().emit(rec)
4109+
4110+
You can use the mixin as in the following script:
4111+
4112+
.. code-block:: python
4113+
4114+
import logging
4115+
4116+
from mymixins import MultilineMixin
4117+
4118+
logger = logging.getLogger(__name__)
4119+
4120+
class StreamHandler(MultilineMixin, logging.StreamHandler):
4121+
pass
4122+
4123+
if __name__ == '__main__':
4124+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-9s %(message)s',
4125+
handlers = [StreamHandler()])
4126+
logger.debug('Single line')
4127+
logger.debug('Multiple lines:\nfool me once ...')
4128+
logger.debug('Another single line')
4129+
logger.debug('Multiple lines:\n%s', 'fool me ...\ncan\'t get fooled again')
4130+
4131+
The script, when run, prints something like:
4132+
4133+
.. code-block:: text
4134+
4135+
2025-07-02 13:54:47,234 DEBUG Single line
4136+
2025-07-02 13:54:47,234 DEBUG Multiple lines:
4137+
2025-07-02 13:54:47,234 DEBUG fool me once ...
4138+
2025-07-02 13:54:47,234 DEBUG Another single line
4139+
2025-07-02 13:54:47,234 DEBUG Multiple lines:
4140+
2025-07-02 13:54:47,234 DEBUG fool me ...
4141+
2025-07-02 13:54:47,234 DEBUG can't get fooled again
4142+
40814143
40824144
.. patterns-to-avoid:
40834145

0 commit comments

Comments
 (0)
0