Skip to content

Commit 0467b1f

Browse files
[3.13] pythongh-94503: Update logging cookbook with an example of uniformly handling newlines in output. (pythonGH-136217) (pythonGH-136358)
(cherry picked from commit d05423a)
1 parent 8f5630d commit 0467b1f

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
@@ -4065,6 +4065,68 @@ lines. With this approach, you get better output:
40654065
WARNING:demo: 1/0
40664066
WARNING:demo:ZeroDivisionError: division by zero
40674067
4068+
How to uniformly handle newlines in logging output
4069+
--------------------------------------------------
4070+
4071+
Usually, messages that are logged (say to console or file) consist of a single
4072+
line of text. However, sometimes there is a need to handle messages with
4073+
multiple lines - whether because a logging format string contains newlines, or
4074+
logged data contains newlines. If you want to handle such messages uniformly, so
4075+
that each line in the logged message appears uniformly formatted as if it was
4076+
logged separately, you can do this using a handler mixin, as in the following
4077+
snippet:
4078+
4079+
.. code-block:: python
4080+
4081+
# Assume this is in a module mymixins.py
4082+
import copy
4083+
4084+
class MultilineMixin:
4085+
def emit(self, record):
4086+
s = record.getMessage()
4087+
if '\n' not in s:
4088+
super().emit(record)
4089+
else:
4090+
lines = s.splitlines()
4091+
rec = copy.copy(record)
4092+
rec.args = None
4093+
for line in lines:
4094+
rec.msg = line
4095+
super().emit(rec)
4096+
4097+
You can use the mixin as in the following script:
4098+
4099+
.. code-block:: python
4100+
4101+
import logging
4102+
4103+
from mymixins import MultilineMixin
4104+
4105+
logger = logging.getLogger(__name__)
4106+
4107+
class StreamHandler(MultilineMixin, logging.StreamHandler):
4108+
pass
4109+
4110+
if __name__ == '__main__':
4111+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-9s %(message)s',
4112+
handlers = [StreamHandler()])
4113+
logger.debug('Single line')
4114+
logger.debug('Multiple lines:\nfool me once ...')
4115+
logger.debug('Another single line')
4116+
logger.debug('Multiple lines:\n%s', 'fool me ...\ncan\'t get fooled again')
4117+
4118+
The script, when run, prints something like:
4119+
4120+
.. code-block:: text
4121+
4122+
2025-07-02 13:54:47,234 DEBUG Single line
4123+
2025-07-02 13:54:47,234 DEBUG Multiple lines:
4124+
2025-07-02 13:54:47,234 DEBUG fool me once ...
4125+
2025-07-02 13:54:47,234 DEBUG Another single line
4126+
2025-07-02 13:54:47,234 DEBUG Multiple lines:
4127+
2025-07-02 13:54:47,234 DEBUG fool me ...
4128+
2025-07-02 13:54:47,234 DEBUG can't get fooled again
4129+
40684130
40694131
.. patterns-to-avoid:
40704132

0 commit comments

Comments
 (0)