Python logging输出JSON日志message为null问题及格式配置方案
问题原因
pythonjsonlogger存在默认处理逻辑:当你直接给日志输出方法(如info()/debug())传入字典类型作为唯一位置参数时,这个字典会被判定为额外扩展字段,所有键值对会直接平铺到最终输出的JSON根结构下,不会被自动赋值给message字段。- 这种传参方式没有给日志传入标准的字符串类型消息内容,
message字段找不到对应填充值,就会输出null。
调整方案
自定义继承JsonFormatter的格式化类,重写字段添加逻辑,自动识别传入的字典类型日志内容,按要求包装到message字段的数组中,同时清理根节点下重复平铺的业务字段,无需修改每一处日志调用代码即可实现目标结构。
可直接运行的调整后代码如下:
import logging from datetime import datetime from pythonjsonlogger import jsonlogger class TargetJsonFormatter(jsonlogger.JsonFormatter): def add_fields(self, log_record, record, message_dict): super().add_fields(log_record, record, message_dict) # 识别传入的字典类型日志内容 if isinstance(record.msg, dict): processed_content = {} # 自动处理datetime等无法直接序列化的类型 for key, value in record.msg.items(): if isinstance(value, datetime): processed_content[key] = value.isoformat() else: processed_content[key] = value # 按要求给message赋值为包裹内容的数组 log_record["message"] = [processed_content] # 清理根节点下被平铺的重复业务字段 for dup_key in processed_content.keys(): if dup_key in log_record: del log_record[dup_key] def setup_logging(log_level): logger = logging.getLogger() logger.setLevel(log_level) # 避免重复添加日志处理器 if logger.handlers: logger.handlers.clear() json_handler = logging.StreamHandler() formatter = TargetJsonFormatter( fmt="%(asctime)s %(levelname)s %(name)s %(message)s" ) json_handler.setFormatter(formatter) logger.addHandler(json_handler) setup_logging(logging.DEBUG) logger = logging.getLogger() StartTime = datetime.now() message_dictionary = { "ApplicationName": "Application ABC", "StartTime": StartTime, } logger.info(message_dictionary)
运行上述代码后,输出日志结构完全匹配要求:
{ "asctime": "2022-06-29 12:08:27,059", "levelname": "INFO", "name": "root", "message": [ { "ApplicationName": "Application ABC", "StartTime": "2022-06-29T12:08:27.059175" } ] }
补充:如果只是单次日志需要输出该结构,不需要全局统一配置,也可以直接在调用日志方法时手动构造消息:
logger.info("", extra={"message": [message_dictionary]}),但这种方式需要修改每一处日志调用,维护成本更高。
内容的提问来源于stack exchange,提问作者Harvesting Data
相关产品推荐
相关产品推荐

