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

如何在Winston自定义Transport中为info对象添加自定义数据?

问题原因分析

  • 递归栈错误:Winston中调用callback(null, info)会将修改后的info重新注入日志流程,导致所有Transport(包括你的CustomTransport和ConsoleTransport)重复处理,形成递归循环。
  • 自定义信息不显示:当前的printf格式化函数没有包含event_id和custom_data字段,所以即使添加了也不会输出到控制台。

解决方案

1. 修复递归错误

不要在callback中传入修改后的info,先创建info的副本进行修改,仅将副本传给webhook,然后调用callback(null)结束当前Transport的处理:

class CustomTransport extends Transport {
  constructor(opts) {
    super(opts);
  }

  log(info, callback) {
    // 创建info副本,避免修改原始对象触发递归
    const modifiedInfo = { ...info };
    modifiedInfo.event_id = 'test';
    modifiedInfo.custom_data = { key1: 'value1' };
    webhook(modifiedInfo);

    // 仅调用callback(null),不返回info,避免触发重复处理
    callback(null);
  }
}

2. 让自定义信息显示在控制台

修改printf格式化函数,将event_id和custom_data添加到输出内容中:

const format = winston.format.combine(
  winston.format.timestamp(),
  winston.format.errors({ stack: true }),
  winston.format.printf((info) => {
    // 构建基础日志内容
    let logStr = winston.format.colorize().colorize(info.level, `[${info.level}] ${info.timestamp} : ${info.message}`);
    
    // 追加自定义字段
    if (info.event_id) {
      logStr += winston.format.colorize().colorize('info', ` | Event ID: ${info.event_id}`);
    }
    if (info.custom_data) {
      logStr += winston.format.colorize().colorize('info', ` | Custom Data: ${JSON.stringify(info.custom_data)}`);
    }
    
    // 追加栈信息(如果存在)
    if (info.stack) {
      logStr += `\n${winston.format.colorize().colorize('error', info.stack)}`;
    }
    
    return logStr;
  }),
);

更优雅的方案:用Winston Format统一添加Metadata

如果希望自定义字段在所有Transport中都能访问,推荐使用Winston的format来添加,更符合框架设计流程,彻底避免递归问题:

// 自定义format:添加全局metadata
const addCustomMetadata = winston.format((info) => {
  info.event_id = 'test';
  info.custom_data = { key1: 'value1' };
  return info;
});

// 组合所有format
const format = winston.format.combine(
  addCustomMetadata(), // 先添加自定义字段
  winston.format.timestamp(),
  winston.format.errors({ stack: true }),
  winston.format.printf((info) => {
    let logStr = winston.format.colorize().colorize(info.level, `[${info.level}] ${info.timestamp} : ${info.message}`);
    
    if (info.event_id) {
      logStr += winston.format.colorize().colorize('info', ` | Event ID: ${info.event_id}`);
    }
    if (info.custom_data) {
      logStr += winston.format.colorize().colorize('info', ` | Custom Data: ${JSON.stringify(info.custom_data)}`);
    }
    
    if (info.stack) {
      logStr += `\n${winston.format.colorize().colorize('error', info.stack)}`;
    }
    
    return logStr;
  }),
);

// 简化CustomTransport,直接使用已添加字段的info
class CustomTransport extends Transport {
  constructor(opts) {
    super(opts);
  }

  log(info, callback) {
    webhook(info);
    callback(null);
  }
}

以上修改后,既不会出现递归错误,自定义的event_id和custom_data也会显示在控制台日志中,同时webhook也能拿到包含自定义字段的日志数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:20:35