You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Logging 自定义Formatter如何支持extra传入自定义字段

Python logging自定义JSON Formatter无法输出自定义字段的解决方案

问题根因

你的判断准确,问题出在原有CustomFormatter的formatMessage方法硬编码了固定的序列化字段列表:无论你通过重写LogRecordFactory添加全局自定义字段,还是通过extra参数传入单次日志的自定义字段,这些字段虽然已经正确挂载到LogRecord实例上,但序列化阶段没有被读取,自然不会出现在最终的JSON输出中。

改造方案

调整Formatter的序列化逻辑:先输出约定的固定基础字段,再自动遍历LogRecord实例上的所有属性,过滤掉原生内置的冗余内部属性后,把所有自定义字段自动追加到输出结构中,同时兼容「全局默认自定义字段」和「extra传参的单次自定义字段」两种场景。

改造后的Formatter代码如下:

import json
import logging
from typing import Optional

# LogRecord原生内置属性集合,用于过滤内部冗余字段
_LOG_RECORD_BUILTIN_ATTRS = {
    "args", "asctime", "created", "exc_info", "exc_text", "filename",
    "funcName", "levelname", "levelno", "lineno", "module", "msecs",
    "message", "msg", "name", "pathname", "process", "processName",
    "relativeCreated", "stack_info", "thread", "threadName",
}

class CustomFormatter(logging.Formatter):

    def __init__(
        self,
        fmt: Optional[str] = "%(asctime)s",
        datefmt: Optional[str] = None,
        style: Optional[str] = "%",
        confidentiality: Optional[str] = "C3",
    ) -> None:
        self.confidentiality = confidentiality
        super().__init__(fmt=fmt, datefmt=datefmt, style=style)

    def formatMessage(self, record: logging.LogRecord, *args, **kwargs) -> str:
        super().formatMessage(record)
        # 组装固定要求的基础日志字段
        log_payload = {
            "asctime": record.asctime,
            "level": record.levelname,
            "name": record.name,
            "message": record.message,
            "timeMillis": int(record.created * 1000),
            "pathName": record.pathname,
            "funcName": record.funcName,
            "lineNumber": record.lineno,
            "confidentiality": self.confidentiality,
        }
        # 自动追加所有自定义字段
        for attr, value in record.__dict__.items():
            if attr not in _LOG_RECORD_BUILTIN_ATTRS and attr not in log_payload:
                log_payload[attr] = value
        
        return json.dumps(log_payload, ensure_ascii=False)

使用说明

  • 原有通过重写LogRecordFactory添加全局自定义字段的逻辑无需修改,改造后全局字段会自动输出。
  • 原生extra传参的调用方式完全兼容,示例:
logger.info("test", extra={"custom_attribute": "my-attr", "user_id": 10086})

运行后输出的JSON会自动追加传入的自定义字段,不需要提前在Formatter中做字段声明。

注意事项

  • 序列化时加了ensure_ascii=False参数,避免中文等非ASCII字符被转义为Unicode编码,提升日志可读性,如有强制ASCII输出要求可删除该参数。
  • 内置属性过滤逻辑已经排除了LogRecord的所有内部冗余字段,不会将异常对象、线程锁这类不可序列化的内部属性输出到日志中。如果需要输出异常栈信息,可以单独在log_payload中添加"exc_text": record.exc_text映射即可。

内容的提问来源于stack exchange,提问作者Data Mastery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:51:26