@@ -4140,6 +4140,42 @@ The script, when run, prints something like:
41404140 2025-07-02 13:54:47,234 DEBUG fool me ...
41414141 2025-07-02 13:54:47,234 DEBUG can't get fooled again
41424142
4143+ If, on the other hand, you are concerned about `log injection
4144+ <https://owasp.org/www-community/attacks/Log_Injection> `_, you can use a
4145+ formatter which escapes newlines, as per the following example:
4146+
4147+ .. code-block :: python
4148+
4149+ import logging
4150+
4151+ logger = logging.getLogger(__name__ )
4152+
4153+ class EscapingFormatter (logging .Formatter ):
4154+ def format (self , record ):
4155+ s = super ().format(record)
4156+ return s.replace(' \n ' , r ' \n ' )
4157+
4158+ if __name__ == ' __main__' :
4159+ h = logging.StreamHandler()
4160+ h.setFormatter(EscapingFormatter(' %(asctime)s %(levelname)-9s %(message)s ' ))
4161+ logging.basicConfig(level = logging.DEBUG , handlers = [h])
4162+ logger.debug(' Single line' )
4163+ logger.debug(' Multiple lines:\n fool me once ...' )
4164+ logger.debug(' Another single line' )
4165+ logger.debug(' Multiple lines:\n %s ' , ' fool me ...\n can\' t get fooled again' )
4166+
4167+ You can, of course, use whatever escaping scheme makes the most sense for you.
4168+ The script, when run, should produce output like this:
4169+
4170+ .. code-block :: text
4171+
4172+ 2025-07-09 06:47:33,783 DEBUG Single line
4173+ 2025-07-09 06:47:33,783 DEBUG Multiple lines:\nfool me once ...
4174+ 2025-07-09 06:47:33,783 DEBUG Another single line
4175+ 2025-07-09 06:47:33,783 DEBUG Multiple lines:\nfool me ...\ncan't get fooled again
4176+
4177+ Escaping behaviour can't be the stdlib default , as it would break backwards
4178+ compatibility.
41434179
41444180.. patterns-to-avoid:
41454181
0 commit comments