【问题标题】:Multi-line logging in PythonPython中的多行日志记录
【发布时间】:2014-05-21 00:09:09
【问题描述】:

我正在使用 Python 3.3.5 和日志记录模块将信息记录到本地文件(来自不同的线程)。在某些情况下,我想输出一些附加信息,但不知道这些信息到底是什么(例如,它可能是单行文本或字典)。

在写入日志记录后,我想做的是将此附加信息添加到我的日志文件中。此外,仅当日志级别为错误(或更高)时才需要附加信息。

理想情况下,它看起来像:

2014-04-08 12:24:01 - INFO     - CPU load not exceeded
2014-04-08 12:24:26 - INFO     - Service is running
2014-04-08 12:24:34 - ERROR    - Could not find any active server processes
Additional information, might be several lines.
Dict structured information would be written as follows:
key1=value1
key2=value2
2014-04-08 12:25:16 - INFO     - Database is responding

没有编写自定义日志格式化程序,我找不到符合我要求的内容。我已经阅读了有关过滤器和上下文的信息,但这似乎又不是一个很好的匹配。

或者,我可以只使用标准 I/O 写入文件,但大部分功能已经存在于 Logging 模块中,而且它是线程安全的。

任何意见将不胜感激。如果确实需要自定义日志格式化程序,那么任何关于从哪里开始的指针都会很棒。

【问题讨论】:

    标签: python logging python-3.x


    【解决方案1】:

    请记住,许多人认为多行日志消息是一种不好的做法(这是可以理解的,因为如果您有像 DataDog 或 Splunk 这样的日志处理器,它们非常准备处理单行日志,多行日志将是很难解析),您可以使用 extra 参数并使用自定义格式化程序将 stuff 附加到将要显示的消息(查看“extra”的用法)在日志包中documentation)。

    import logging
    
    class CustomFilter(logging.Filter):
        def filter(self, record):
            if hasattr(record, 'dct') and len(record.dct) > 0:
                for k, v in record.dct.iteritems():
                    record.msg = record.msg + '\n\t' + k + ': ' + v
            return super(CustomFilter, self).filter(record)
            
    if __name__ == "__main__":
        logging.getLogger().setLevel(logging.DEBUG)
        extra_logger = logging.getLogger('extra_logger')
        extra_logger.setLevel(logging.INFO)
        extra_logger.addFilter(CustomFilter())
        logging.debug("Nothing special here... Keep walking")
        extra_logger.info("This shows extra",
                          extra={'dct': {"foo": "bar", "baz": "loren"}})
        extra_logger.debug("You shouldn't be seeing this in the output")
        extra_logger.setLevel(logging.DEBUG)
        extra_logger.debug("Now you should be seeing it!")
        
    

    该代码输出:

    DEBUG:root:Nothing special here... Keep walking
    INFO:extra_logger:This shows extra
            foo: bar
            baz: loren
    DEBUG:extra_logger:Now you should be seeing it!
    

    我仍然建议在您的自定义过滤器中调用super 的filter 函数,主要是因为这是决定是否显示消息的函数(例如,如果您的记录器的级别设置为logging.INFO,如果您使用extra_logger.debug 记录某些内容,则不应看到该消息,如上例所示)

    【讨论】:

      【解决方案2】:

      我在较小的应用程序中使用了一个简单的分行器:

      for line in logmessage.splitlines():
                  writemessage = logtime + " - " + line + "\n"
                  logging.info(str(writemessage))
      

      请注意,这不是线程安全的,可能只应在日志量日志记录应用程序中使用。

      但是,您几乎可以输出以记录任何内容,因为它会保留您的格式。例如,我使用它来输出 JSON API 响应,格式为:json.dumps(parsed, indent=4, sort_keys=True)

      【讨论】:

        【解决方案3】:

        我在定义 LogFormatter 字符串时似乎犯了一个小错误:由于不小心转义了换行符,我错误地认为不可能将多行输出写入日志文件。

        感谢@Barafu 指出这一点(这就是我给他分配正确答案的原因)。

        示例代码如下:

        import logging
        lf = logging.Formatter('%(levelname)-8s - %(message)s\n%(detail)s')
        lh = logging.FileHandler(filename=r'c:\temp\test.log')
        lh.setFormatter(lf)
        log = logging.getLogger()
        log.setLevel(logging.DEBUG)
        log.addHandler(lh)
        log.debug('test', extra={'detail': 'This is a multi-line\ncomment to test the formatter'})
        

        生成的输出如下所示:

        DEBUG    - test
        This is a multi-line
        comment to test the formatter
        

        警告:

        如果没有要记录的详细信息,并且您传递一个空字符串,记录器仍将输出换行符。因此,剩下的问题是:我们如何才能使这个有条件?

        一种方法是在实际记录信息之前更新记录格式化程序,如here 所述。

        【讨论】:

          【解决方案4】:

          我只是在输出文本中添加\n 符号。

          【讨论】:

          • 如果我将日志格式化程序定义为lf = logging.Formatter('%(levelname)-8s - %(message)s\\n%(detail)s') 并定义FileHandler 将日志写入文件,则输出将包含\n 而不是转换为换行符。
          • 关注“日志记录手册”。使用 str.format() 样式作为模板而不是默认的基于 % 的样式 - 然后它将尊重特殊符号。
          猜你喜欢
          • 1970-01-01
          • 2011-07-24
          • 2020-07-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-26
          • 1970-01-01
          相关资源
          最近更新 更多