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

问题描述 投票:0回答:4

所以我可以像这样向我的日志消息添加其他字段

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
}
python python-3.x logging
4个回答
4
投票

如果您阅读

logging.Logger.makeRecord
方法的源代码,该方法返回一个带有给定日志信息的
LogRecord
对象,您会发现它将
extra
字典与返回的
__dict__
属性合并在一起。
LogRecord
对象,因此您无法在格式化程序中检索原始
extra
字典。

相反,您可以使用包装函数来修补

logging.Logger.makeRecord
方法,该函数将给定的
extra
字典存储为返回
_extra
对象的
LogRecord
属性:

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


2
投票

我想到了两种方法:

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

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()

0
投票

可以使用与这个答案类似的方法,其中字典key,即

extra_info
,用于将所有额外数据传递给它。然后,在自定义
formatter
中,可以查找该 key,以便提取数据并将其添加到记录中。

工作示例

import logging, json


class CustomJSONFormatter(logging.Formatter):
    def __init__(self, formatter):
        logging.Formatter.__init__(self, formatter)

    def format(self, record):
        logging.Formatter.format(self, record)
        return json.dumps(get_log(record), indent=2)


def get_log(record):
    d = {
        "time": record.asctime,
        "level": record.levelname,
        "message": record.message,
    }

    if hasattr(record, "extra_info"):
        d["foo"] = record.extra_info["foo"]

    return d


logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(CustomJSONFormatter('%(asctime)s'))
logger.addHandler(handler)
logger.info("test", extra={"extra_info": {"foo": "bar"}})
© www.soinside.com 2019 - 2024. All rights reserved.