Python如何仅为单个handler配置自定义json_logging格式化器
解决方案
第一步:实现自定义JSON格式化类
直接继承json_logging.JSONLogFormatter,不需要调用任何全局初始化方法,在类中自定义你需要的字段规则:
import json_logging import logging class CustomJSONLogFormatter(json_logging.JSONLogFormatter): def _get_log_record_attrs(self, record): # 先获取默认的所有字段 attrs = super()._get_log_record_attrs(record) # 删除不需要的冗余字段 redundant_fields = ["module", "line_no", "func_name", "process_name", "thread_name"] for field in redundant_fields: attrs.pop(field, None) # 可自行添加需要的自定义字段 # attrs["custom_field"] = "your_value" return attrs
如果你是因为封装了日志工具函数导致module、line_no字段不准,不需要直接删字段,可以在你封装的日志调用处添加stacklevel参数解决(Python 3.7原生支持):
# 你的自定义日志工具函数 def my_log_info(msg): # stacklevel=2 会跳过当前封装函数层,取上层调用位置的信息 logging.info(msg, stacklevel=2)
第二步:仅给指定handler绑定自定义格式化器
有两种实现方式,选其中一种即可:
方式1:直接修改YAML配置(推荐)
不需要额外写Python代码修改handler,直接把你的自定义格式化类的全路径填到YAML的file_formatter的class字段即可:
formatters: console_formatter: format: "%(asctime)s %(process)d %(thread)d %(levelname)s %(message)s" datefmt: "%Y-%m-%dT%H:%M:%S%z" file_formatter: format: "%(asctime)s %(process)d %(thread)d %(levelname)s %(message)s" datefmt: "%Y-%m-%dT%H:%M:%S" # 替换为你自定义格式化类的实际全路径,比如类写在myapp.utils模块下就填myapp.utils.CustomJSONLogFormatter class: myapp.utils.CustomJSONLogFormatter
修改完后原有的dictConfig加载逻辑不需要做任何改动,会自动给文件handler绑定自定义JSON格式化器,控制台handler不受影响。
方式2:加载配置后手动修改handler
如果不想改YAML配置,可以在logging.config.dictConfig执行完成后,手动遍历handler替换文件handler的格式化器即可,不要调用json_logging.init_non_web等全局初始化方法:
if path is None: logging.warning("Log configuration file NOT found: " + ','.join([value, default_path, package_path])) logging.basicConfig(level=default_level, format=format) else: logging.debug("Log configuration file found: " + path) with open(path, 'rt') as f: config = yaml.safe_load(f.read()) logging.config.dictConfig(config) # 新增代码:仅替换文件handler的格式化器 root_logger = logging.getLogger() for handler in root_logger.handlers: if isinstance(handler, logging.FileHandler): # 直接实例化自定义格式化器绑定,不需要调用任何json_logging的全局init方法 handler.setFormatter(CustomJSONLogFormatter())
原理说明
你之前的方法出错是因为json_logging.init_non_web等init_*系列方法是全局初始化接口,会自动给所有已存在、后续创建的handler都绑定JSON格式化器,才会导致控制台也输出JSON格式。你不需要调用这些全局方法,单独实例化自定义的格式化类给指定handler绑定即可。
内容的提问来源于stack exchange,提问作者user3501221
相关产品推荐
相关产品推荐

