在不使用event参数时,如何用structlog设置日志级别?
问题描述
在structlog中创建仅输出指定级别及以上日志的记录器,惯用方式是使用:
wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
这种方式正常工作,但在以下使用模式下会失效:
l = logger.bind(event="get_tar", key=value) l.info(status="download_start") buf = f.read() l.info(status="download_finish")
默认使用logfmt格式时,structlog会将"message"作为event键输出,因此直接通过bind设置了该键。但这种方式失效的原因是make_filtering_bound_logger底层实现要求必须传入event参数,其核心代码如下:
def make_method(level: int) -> Callable[..., Any]: if level < min_level: return _nop name = _LEVEL_TO_NAME[level] def meth(self: Any, event: str, **kw: Any) -> Any: return self._proxy_to_logger(name, event, **kw) meth.__name__ = name return meth
请问是否有解决方法?
解决方法
方案1:调用日志方法时显式传入空event参数
既然底层要求必须有event参数,调用info()等方法时可以传空字符串或占位符,绑定的event值依然会生效:
l = logger.bind(event="get_tar", key=value) l.info("", status="download_start") # 显式传入空event参数 buf = f.read() l.info("", status="download_finish")
方案2:自定义过滤绑定日志器
如果不想每次都传空event,可以自己实现兼容bind(event=...)场景的过滤日志器,修改底层方法允许从绑定上下文获取event:
import structlog from structlog._log_levels import _LEVEL_TO_NAME from typing import Callable, Any def make_custom_filtering_bound_logger(min_level: int): class CustomFilteringBoundLogger(structlog.BoundLoggerBase): def __init__(self, logger, processors, context): super().__init__(logger, processors, context) def make_method(level: int) -> Callable[..., Any]: if level < min_level: return lambda self, *args, **kw: None name = _LEVEL_TO_NAME[level] def meth(self: Any, event: str = None, **kw: Any) -> Any: # 未传event时,从上下文获取 if event is None: event = self._context.get("event", "") return self._proxy_to_logger(name, event, **kw) meth.__name__ = name return meth # 为各日志级别绑定对应方法 for level in _LEVEL_TO_NAME: method = make_method(level) setattr(CustomFilteringBoundLogger, _LEVEL_TO_NAME[level], method) return CustomFilteringBoundLogger
使用时替换原有的make_filtering_bound_logger:
wrapper_class=make_custom_filtering_bound_logger(logging.INFO),
之后即可按原有方式调用:
l = logger.bind(event="get_tar", key=value) l.info(status="download_start") l.info(status="download_finish")
方案3:添加处理器补全event字段
保留make_filtering_bound_logger不变,通过自定义处理器补全缺失的event字段:
def fill_event_processor(logger, method_name, event_dict): # 若event不存在,从上下文或默认值补充 if "event" not in event_dict: event_dict["event"] = event_dict.get("event", "") return event_dict
配置structlog时添加该处理器:
structlog.configure( processors=[ fill_event_processor, structlog.processors.LogfmtRenderer(), # 对应logfmt格式渲染器 ], wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), )
这种方式无需修改调用逻辑,由处理器自动处理event字段的补全。
内容的提问来源于stack exchange,提问作者Foobar
相关产品推荐
相关产品推荐

