动态调整日志记录格式

时间:2016-11-15 21:18:58

标签: python logging

我想为python程序创建一个记录器,它在程序运行期间改变其格式。这是必要的,因为我希望记录器显示除了日志消息之外当前正在运行的程序部分的信息。 我想要的是这样的事情(程序的不同部分 - 第一部分,第二部分应该被记录):

2016-11-15 21:09:07,042 - MyProgram - INFO - First Part - One log message
2016-11-15 21:09:07,042 - MyProgram - INFO - Second Part - Another log message

我尝试了以下代码:

import logging

#Set up logger
logfile = str('example.log')
logger = logging.getLogger('MyProgram')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(logfile)
fh.setLevel(logging.INFO)

ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

log_status = 'First Part'
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - {0} - %(message)s'.format(log_status))

fh.setFormatter(formatter)
ch.setFormatter(formatter)


logger.addHandler(fh)
logger.addHandler(ch)

#First part of the program
logger.info("One log message")

#Second part of the program
log_status = 'Second Part'

logger.info("Another log message")

我得到的是以下内容:

2016-11-15 21:09:07,042 - MyProgram - INFO - First Part - One log message
2016-11-15 21:09:07,042 - MyProgram - INFO - First Part - Another log message

我怎样才能解决这个问题 - 最好是优雅的?不要犹豫,为我的其余代码提供建议。

2 个答案:

答案 0 :(得分:3)

您的解决方案无效,因为当您致电'%(asctime)s - %(name)s - %(levelname)s - {0} - %(message)s'.format(log_status)时,会创建一个新字符串并将其传递给Formatter,而log_status永远不会再使用。您需要一个自定义Formatter来动态创建格式字符串。

但是看看这个问题是如何在Python官方文档中解决的:Logging Cookbook: Adding contextual information to your logging output - 请参阅自定义logging.Filter的示例。

import logging
from random import choice

class ContextFilter(logging.Filter):
    """
    This is a filter which injects contextual information into the log.

    Rather than use actual contextual information, we just use random
    data in this demo.
    """

    USERS = ['jim', 'fred', 'sheila']
    IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1']

    def filter(self, record):

        record.ip = choice(ContextFilter.IPS)
        record.user = choice(ContextFilter.USERS)
        return True

if __name__ == '__main__':
    levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s')
    a1 = logging.getLogger('a.b.c')
    a2 = logging.getLogger('d.e.f')

    f = ContextFilter()
    a1.addFilter(f)
    a2.addFilter(f)
    a1.debug('A debug message')
    a1.info('An info message with %s', 'some parameters')
    for x in range(10):
        lvl = choice(levels)
        lvlname = logging.getLevelName(lvl)
        a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')

输出:

2010-09-06 22:38:15,292 a.b.c DEBUG    IP: 123.231.231.123 User: fred     A debug message
2010-09-06 22:38:15,300 a.b.c INFO     IP: 192.168.0.1     User: sheila   An info message with some parameters
2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1       User: sheila   A message at CRITICAL level with 2 parameters
2010-09-06 22:38:15,300 d.e.f ERROR    IP: 127.0.0.1       User: jim      A message at ERROR level with 2 parameters
...

答案 1 :(得分:0)

扩展 Messa's answer,您可以更改 ContextFilter 类实例的属性,而该更改将影响输出。对于您的示例代码如下:

import logging


class ContextFilter(logging.Filter):
    def __init__(self):
        super().__init__()

        self._log_status = ""

    def set_status(self, status: str):
        self._log_status = status

    def filter(self, record: logging.LogRecord) -> bool:
        record.log_status = self._log_status
        return True


# Set up logger
logfile = str('example.log')
logger = logging.getLogger('MyProgram')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(logfile)
fh.setLevel(logging.INFO)

ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(log_status)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

# Now we need to add filters to handlers
f = ContextFilter()
f.set_status("First Part")
fh.addFilter(f)
ch.addFilter(f)

logger.addHandler(fh)
logger.addHandler(ch)

# First part of the program
logger.info("One log message")

# Second part of the program
f.set_status("Second Part")

logger.info("Another log message")

这段代码给出了你想要的确切输出:

2021-01-16 20:49:18,848 - MyProgram - INFO - First Part - One log message
2021-01-16 20:49:18,848 - MyProgram - INFO - Second Part - Another log message