在日志格式化程序中提取日志调用中的额外字段

5
所以我可以像这样将额外的字段添加到我的日志消息中
logging.info("My log Message", extra={"someContext":1, "someOtherContext":2})

很好,但不清楚如何在我的日志格式化器中提取所有额外字段。

def format(self, record):
  record_dict = record.__dict__.copy()
  print(record_dict)

在上面的代码中,我可以看到所有额外字段在输出字典中,但是它们被压缩成一个带有许多其他不需要的垃圾信息的字典。
{'name': 'root', 'msg': 'My log Message', 'args': (), 'levelname': 'INFO', 'levelno': 20, 'pathname': '.\\handler.py', 'filename': 'handler.py', 'module': 'handler', 'exc_info': None, 'exc_text': None, 'stack_info': None, 'lineno': 27, 'funcName': 'getPlan', 'created': 1575461352.0664868, 'msecs': 66.48683547973633, 'relativeCreated': 1253.0038356781006, 'thread': 15096, 'threadName': 'MainThread', 'processName': 'MainProcess', 'process': 23740, 'someContext': 1, 'someOtherContext':2}

有没有一种方法可以获取我所有的额外键,而无需提前知道它们?

我正在编写一个JSON格式化程序,想要创建一个类似于字典的东西。

justMyExtra = ?????
to_log = {
"message" record_dict["message"], 
**justMyExtra
}
3个回答

2

有两种方法:

  1. 将所有额外的字段转储到主字典中的字典中。将键命名为“additionalContext”并获取所有额外的条目。
  2. 创建原始字典的副本,并删除所有已知键:'name'、'msg'、'args'等,直到只剩下你自己的额外字段。

1
如果您阅读logging.Logger.makeRecord方法的源代码,该方法返回一个LogRecord对象,其中包含给定的日志信息,您会发现它将extra字典与返回的LogRecord对象的__dict__属性合并在一起,因此您无法在格式化程序中检索原始的extra字典。
相反,您可以使用包装函数修补logging.Logger.makeRecord方法,将给定的extra字典存储为返回的LogRecord对象的_extra属性。
def make_record_with_extra(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):
    record = original_makeRecord(self, name, level, fn, lno, msg, args, exc_info, func, extra, sinfo)
    record._extra = extra
    return record

original_makeRecord = logging.Logger.makeRecord
logging.Logger.makeRecord = make_record_with_extra

所以:
class myFormatter(logging.Formatter):
    def format(self, record):
        print('Got extra:', record._extra) # or do whatever you want with _extra
        return super().format(record)

logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(myFormatter('%(name)s - %(levelname)s - %(message)s - %(foo)s'))
logger.addHandler(handler)
logger.warning('test', extra={'foo': 'bar'})

输出:

Got extra: {'foo': 'bar'}
__main__ - WARNING - test - bar

演示:https://repl.it/@blhsing/WorthyTotalLivedistro


1
修补makeRecord不是一种通用或理想的解决方案。此时程序员没有使用内置记录器,这可能会损害中间件互操作性。 - John Vandivier

0

@james-hendricks类似的两种方法,但稍微不那么脆弱:

  1. 使用LogRecord上现有的args字典,而不是自己想出一个字典。
  2. 创建一个虚拟的LogRecord并检查其键,以获取一个非脆弱的LogRecord特殊键的str列表:
  dummy = logging.LogRecord('dummy', 0, 'dummy', 0, None, None, None, None, None)
  reserved_keys = dummy.__dict__.keys()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接