首页 文章

如何将自定义字段添加到Python日志格式字符串?

提问于
浏览
53

我当前的格式字符串是:

formatter = logging.Formatter('%(asctime)s : %(message)s')

我想添加一个名为app_name的新字段,它将在包含此格式化程序的每个脚本中具有不同的值 .

import logging
formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
syslog.setFormatter(formatter)
logger.addHandler(syslog)

但我不知道如何将 app_name 值传递给 Logger 以插入格式字符串 . 我显然可以让它出现在日志消息中,但每次都传递它,但这很麻烦 .

我试过了:

logging.info('Log message', app_name='myapp')
logging.info('Log message', {'app_name', 'myapp'})
logging.info('Log message', 'myapp')

但没有工作 .

3 回答

  • 77

    您可以使用LoggerAdapter,这样您就不必在每次记录调用时都传递额外的信息:

    import logging
    extra = {'app_name':'Super App'}
    
    logger = logging.getLogger(__name__)
    syslog = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
    syslog.setFormatter(formatter)
    logger.setLevel(logging.INFO)
    logger.addHandler(syslog)
    
    logger = logging.LoggerAdapter(logger, extra)
    logger.info('The sky is so blue')
    

    日志(类似的东西)

    2013-07-09 17:39:33,596 Super App : The sky is so blue
    

    Filters也可用于添加上下文信息 .

    import logging
    
    class AppFilter(logging.Filter):
        def filter(self, record):
            record.app_name = 'Super App'
            return True
    
    logger = logging.getLogger(__name__)
    logger.addFilter(AppFilter())
    syslog = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
    syslog.setFormatter(formatter)
    logger.setLevel(logging.INFO)
    logger.addHandler(syslog)
    
    logger.info('The sky is so blue')
    

    产生类似的日志记录 .

  • 3

    你需要将dict作为参数传递给extra,以便那样做 .

    logging.info('Log message', extra={'app_name': 'myapp'})
    

    证明:

    >>> import logging
    >>> logging.basicConfig(format="%(foo)s - %(message)s")
    >>> logging.warning('test', extra={'foo': 'bar'})
    bar - test
    

    另外,作为注释,如果您尝试在不传递dict的情况下记录消息,那么它将失败 .

    >>> logging.warning('test')
    Traceback (most recent call last):
      File "/usr/lib/python2.7/logging/__init__.py", line 846, in emit
        msg = self.format(record)
      File "/usr/lib/python2.7/logging/__init__.py", line 723, in format
        return fmt.format(record)
      File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
        s = self._fmt % record.__dict__
    KeyError: 'foo'
    Logged from file <stdin>, line 1
    
  • 25

    另一种方法是创建自定义LoggerAdapter . 当您无法更改格式时,或者如果您的格式与不发送唯一键的代码共享(在您的案例中为app_name),这将非常有用:

    class LoggerAdapter(logging.LoggerAdapter):
        def __init__(self, logger, prefix):
            super(LoggerAdapter, self).__init__(logger, {})
            self.prefix = prefix
    
        def process(self, msg, kwargs):
            return '[%s] %s' % (self.prefix, msg), kwargs
    

    在您的代码中,您将像往常一样创建并初始化您的 Logger :

    logger = logging.getLogger(__name__)
        # Add any custom handlers, formatters for this logger
        myHandler = logging.StreamHandler()
        myFormatter = logging.Formatter('%(asctime)s %(message)s')
        myHandler.setFormatter(myFormatter)
        logger.addHandler(myHandler)
        logger.setLevel(logging.INFO)
    

    最后,您将创建包装器适配器以根据需要添加前缀:

    logger = LoggerAdapter(logger, 'myapp')
        logger.info('The world bores you when you are cool.')
    

    输出看起来像这样:

    2013-07-09 17:39:33,596 [myapp] The world bores you when you are cool.
    

相关问题