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

在winston.format.combine中使用ecsFormat与自定义格式提供者遇JSON循环结构错误求解决

解决Winston组合ecsFormat与自定义格式时的循环引用JSON错误

错误原因

TypeError: Converting circular structure to JSON 是因为日志对象中存在循环引用(比如对象A引用对象B,B又反向引用A),当ecsFormat或自定义格式尝试将该对象序列化为JSON时触发异常。

可行解决方案

1. 定位循环引用来源

  • 单独测试格式组件:先分别只启用ecsFormat或自定义格式,确认是哪部分引入了循环结构。比如:
    // 测试ecsFormat单独使用
    this.logger = winston.createLogger({
      level: this.level,
      format: ecsFormat(),
      transports: [new Console()],
    });
    
  • 打印调试日志:在自定义格式中用Node.js内置的util.inspect查看完整日志对象,定位循环引用的属性:
    const util = require('util');
    
    // 在自定义格式生成函数中添加
    const createFormat = (category) => {
      return winston.format((info) => {
        // 打印完整对象,depth: null显示所有层级
        console.log(util.inspect(info, { depth: null }));
        info.category = category;
        return info;
      })();
    };
    

2. 清理日志对象中的循环引用

实现一个工具函数,递归移除或标记循环引用的属性,再传入格式处理:

function cleanCircularReferences(obj, seen = new WeakSet()) {
  if (typeof obj !== 'object' || obj === null) return obj;
  if (seen.has(obj)) return '[Circular Reference]';
  
  seen.add(obj);
  const cleaned = Array.isArray(obj) ? [] : {};
  
  for (const key in obj) {
    cleaned[key] = cleanCircularReferences(obj[key], seen);
  }
  
  seen.delete(obj);
  return cleaned;
}

// 在格式组合中优先处理循环引用
this.logger = winston.createLogger({
  level: this.level,
  format: winston.format.combine(
    winston.format(info => cleanCircularReferences(info))(),
    ecsFormat(),
    this.formatProvider.createFormat(this.category)
  ),
  transports: [new Console()],
});

3. 配置ecsFormat排除/处理循环字段

ecsFormat默认可能捕获HTTP请求/响应这类自带循环引用的对象,可通过配置过滤:

  • 排除指定字段:
    ecsFormat({
      exclude: ['req', 'res'] // 移除可能带循环的请求/响应对象
    })
    
  • 自定义字段转换:只保留需要的属性,避免序列化整个对象:
    ecsFormat({
      transform: (info) => {
        if (info.req) {
          // 仅保留请求的关键属性
          info.req = {
            method: info.req.method,
            url: info.req.url,
            remoteAddress: info.req.connection.remoteAddress
          };
        }
        return info;
      }
    })
    

4. 调整自定义格式逻辑

如果是自定义格式生成的字段导致循环,直接修改逻辑:

  • 避免将完整的复杂对象(如req、res、数据库连接实例)加入日志,只提取需要的属性值。
  • 检查自定义格式中是否有相互引用的字段,比如info.parent = info这类错误赋值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:57:21