【问题标题】:How to print multiline logs using python logging module?如何使用 python 日志记录模块打印多行日志?
【发布时间】:2017-12-26 06:37:00
【问题描述】:

我想使用 python 日志模块创建多行记录器。当我使用下面的代码 sn-p 格式化记录器时:

import logging
logger = logging.getLogger(file_name)
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)

当我使用 logger.info("""line 1\nline 2\n line 3""")

p>
2017-07-20 13:21:14,754 - my_logger.py - INFO - line 1
line 2
line 3

我希望我的输出如下:

2017-07-20 13:21:14,754 - my_logger.py - INFO - line 1
2017-07-20 13:21:14,754 - my_logger.py - INFO - line 2
2017-07-20 13:21:14,754 - my_logger.py - INFO - line 3

【问题讨论】:

  • 您是否有理由不能多次调用logger.info()
  • @Jakub 我想为框架创建一个记录器,并希望拥有这种格式化程序。

标签: python python-2.7 python-3.x logging


【解决方案1】:

调整 @Qeek 的答案,以便我们可以在所有行中支持 % 替换

test_logger.info("foo %s foo %s \nfoo %s", "bar","bar", "bar")    

考虑到这些可以添加到 % diouxXeEfFgGcrsa 的字符

https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting

import logging
import re

class MultilineFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord):
        save_msg = record.msg
        args = list(record.args)
        output = ""
        for line in save_msg.splitlines():
            record.msg = line
            number_of_string_subs = len(re.findall(r"%[diouxXeEfFgGcrsa]", line))
            record.args = tuple(args[:number_of_string_subs])
            args = args[number_of_string_subs:]
            output += super().format(record) + "\n"
        record.msg = save_msg
        record.message = output
        return output

比修改你的记录器初始化如下:

formatter = MultilineFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

【讨论】:

    【解决方案2】:

    如果我只使用单个日志级别(警告或信息或类似),我更愿意使用辅助函数来执行此操作:

    def multiline_warning(header, body):
      for line in body.splitlines():
        logging.warning(f"{header}: {line}")
    

    在上下文中,只需调用:

    multiline_warning("stderr", subprocess_result.stderr)
    

    如果使用不止一种(CRITICAL、ERROR、WARNING、INFO 或 DEBUG),您可以抽象日志级别并将其作为参数传递,并改用 logging.log。

    【讨论】:

      【解决方案3】:

      您可以创建自己的格式化程序:

      import logging
      class MultilineFormatter(logging.Formatter):
          def format(self, record: logging.LogRecord):
              save_msg = record.msg
              output = ""
              for line in save_msg.splitlines():
                  record.msg = line
                  output += super().format(record) + "\n"
              record.msg = save_msg
              record.message = output
              return output
      

      比修改你的记录器初始化如下:

      formatter = MultilineFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
      

      【讨论】:

      • 这里警告! test_logger.info("foo %s \nfoo %s", "bar", "bar") 如果您进行多行 % 替换,这将不起作用。我会寻找这个答案的扩展
      • 在下面添加了我的
      【解决方案4】:

      简短的回答,你不能。您可以做的事情如下:

      logger.info('line 1')
      logger.info('line 2')
      logger.info('line 3')
      

      或者如果你有多行的东西,你可以这样做:

      map(logger.info, 'line 1\nline 2\nline 3'.split('\n'))
      

      这些不会同时出现,但会非常接近...

      【讨论】:

      • 请注意,由于 map 很懒,后者仅适用于 py2;你可以在 py3 上做[logger.info(line) for line in 'line 1\nline 2\nline 3'.splitlines()]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      • 2020-08-11
      • 2013-08-15
      • 1970-01-01
      • 2017-06-04
      相关资源
      最近更新 更多