8000 gh-94503: Update logging cookbook with an example of uniformly handli… by vsajip · Pull Request #136217 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-94503: Update logging cookbook with an example of uniformly handli… #136217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions Doc/howto/logging-cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,68 @@ lines. With this approach, you get better output:
WARNING:demo: 1/0
WARNING:demo:ZeroDivisionError: division by zero

How to uniformly handle newlines in logging output
--------------------------------------------------

Usually, messages that are logged (say to console or file) consist of a single
line of text. However, sometimes there is a need to handle messages with
multiple lines - whether because a logging format string contains newlines, or
logged data contains newlines. If you want to handle such messages uniformly, so
that each line in the logged message appears uniformly formatted as if it was
logged separately, you can do this using a handler mixin, as in the following
snippet:

.. code-block:: python

# Assume this is in a module mymixins.py
import copy

class MultilineMixin:
def emit(self, record):
s = record.getMessage()
if '\n' not in s:
super().emit(record)
else:
lines = s.splitlines()
rec = copy.copy(record)
rec.args = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be an issue where someone uses .args?

for line in lines:
rec.msg = line
super().emit(rec)

You can use the mixin as in the following script:

.. code-block:: python

import logging

from mymixins import MultilineMixin

logger = logging.getLogger(__name__)

class StreamHandler(MultilineMixin, logging.StreamHandler):
pass

if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-9s %(message)s',
handlers = [StreamHandler()])
logger.debug('Single line')
logger.debug('Multiple lines:\nfool me once ...')
logger.debug('Another single line')
logger.debug('Multiple lines:\n%s', 'fool me ...\ncan\'t get fooled again')

The script, when run, prints something like:

.. code-block:: text

2025-07-02 13:54:47,234 DEBUG Single line
2025-07-02 13:54:47,234 DEBUG Multiple lines:
2025-07-02 13:54:47,234 DEBUG fool me once ...
2025-07-02 13:54:47,234 DEBUG Another single line
2025-07-02 13:54:47,234 DEBUG Multiple lines:
2025-07-02 13:54:47,234 DEBUG fool me ...
2025-07-02 13:54:47,234 DEBUG can't get fooled again


.. patterns-to-avoid:

Expand Down
Loading
0