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
+ 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: