Python:设置日志记录,允许多行字符串:logging.info(' foo \ nbar')

时间:2018-03-01 11:45:44

标签: python logging

到目前为止,我只是简单地记录到文件,如果我记录多行字符串,那么结果如下所示:

发送日志:

logging.info('foo\nbar') 

日志文件:

2018-03-05 10:51:53 root.main +16: INFO     [28302] foo

到目前为止,所有不包含" INFO"或" DEBUG"报告给运营商。

这意味着会报告bar行。这是误报。

环境:Linux。

如何在Python中设置日志记录以将INFO foo\nbar保留在一个字符串中并忽略整个字符串,因为它只是" INFO"?

注意:是的,您可以过滤解释器中的日志记录。不幸的是,这不是问题所在。这个问题不同。首先记录日志。然后解析日志。

这是一个重现它的脚本:

import sys
import logging


def set_up_logging(level=logging.INFO):
    root_logger = logging.getLogger()
    root_logger.setLevel(level)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(
        logging.Formatter('%(asctime)s %(name)s: %(levelname)-8s [%(process)d] %(message)s', '%Y-%m-%d %H:%M:%S'))
    root_logger.addHandler(handler)


def main():
    set_up_logging()
    logging.info('foo\nbar')


if __name__ == '__main__':
    main()

再次考虑之后,我认为真正的问题是:哪种日志格式可行?只是删除跨越多行的消息中的换行符会使人眼难以阅读某些输出。另一方面,logging.info()与日志文件中的一行之间的当前1:1关系易于阅读。 ......我不确定

3 个答案:

答案 0 :(得分:6)

我通常有一个自定义日志记录的类,但您可以使用自定义logging.Formatter实现所需的目标:

import logging

class NewLineFormatter(logging.Formatter):

    def __init__(self, fmt, datefmt=None):
        """
        Init given the log line format and date format
        """
        logging.Formatter.__init__(self, fmt, datefmt)


    def format(self, record):
        """
        Override format function
        """
        msg = logging.Formatter.format(self, record)

        if record.message != "":
            parts = msg.split(record.message)
            msg = msg.replace('\n', '\n' + parts[0])

        return msg

上面的format()函数拆分行并复制每行中的timestamp / logging-preamble(每\n之后)

现在您需要将格式化程序附加到根记录器。如果您构建自己的日志记录设置/结构,您实际上可以将它附加到任何handler

# Basic config as usual
logging.basicConfig(level=logging.DEBUG)

# Some globals/consts
DATEFORMAT = '%d-%m-%Y %H:%M:%S'
LOGFORMAT = '%(asctime)s %(process)s %(levelname)-8s %(filename)15s-%(lineno)-4s: %(message)s'

# Create a new formatter
formatter = NewLineFormatter(LOGFORMAT, datefmt=DATEFORMAT)

# Attach the formatter on the root logger
lg = logging.getLogger()

# This is a bit of a hack... might be a better way to do this
lg.handlers[0].setFormatter(formatter)


# test root logger
lg.debug("Hello\nWorld")

# test module logger + JSON
lg = logging.getLogger("mylogger")
lg.debug('{\n    "a": "Hello",\n    "b": "World2"\n}')

上面给出了:

05-03-2018 08:37:34 13065 DEBUG     test_logger.py-47  : Hello
05-03-2018 08:37:34 13065 DEBUG     test_logger.py-47  : World
05-03-2018 08:37:34 13065 DEBUG     test_logger.py-51  : {
05-03-2018 08:37:34 13065 DEBUG     test_logger.py-51  :     "a": "Hello",
05-03-2018 08:37:34 13065 DEBUG     test_logger.py-51  :     "b": "World2"
05-03-2018 08:37:34 13065 DEBUG     test_logger.py-51  : }

请注意,我正在访问根记录器的.handlers[0],这有点像黑客但我无法找到解决方法...另外,请注意格式化的JSON打印:)

答案 1 :(得分:3)

我认为保持这种1:1的关系,每个logging.info()调用的日志文件中只有一行,非常希望保持日志文件的简单性和可解析性。因此,如果您确实需要记录换行符,那么我只需记录字符串表示,例如:

logging.info(repr('foo\nbar'))

输出:

2018-03-05 11:34:54 root: INFO     [32418] 'foo\nbar'

一个简单的替代方案是分别记录每个部分:

log_string = 'foo\nbar'
for item in log_string.split('\n'):
    logging.info(item)

输出:

2018-03-05 15:39:44 root: INFO     [4196] foo
2018-03-05 15:39:44 root: INFO     [4196] bar

答案 2 :(得分:2)

您可以使用:

logging.basicConfig(level=your_level)

其中your_level是其中之一:

  'debug': logging.DEBUG,
  'info': logging.INFO,
  'warning': logging.WARNING,
  'error': logging.ERROR,
  'critical': logging.CRITICAL

在您的情况下,您可以使用警告忽略信息

import logging
logging.basicConfig(filename='example.log',level=logging.WARNING)

logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

Output:
WARNING:root:And this, too

您可以尝试在记录为

之前禁用INFO
import logging
logging.basicConfig(filename='example.log')

logging.debug('This message should go to the log file')
logging.disable(logging.INFO)
logging.info('So should this')
logging.disable(logging.NOTSET)
logging.warning('And this, too')
Output:
WARNING:root:And this, too

或者

logger.disabled = True
someOtherModule.function()
logger.disabled = False