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

迁移至Winston 3.x扩展自定义Logger时重写log方法不生效问题

问题根因

你的代码不生效有两个核心原因:

  • 继承对象错误:Winston 3.x 中的winston.createLogger是工厂函数,不是构造类,对它做extends继承无法拿到正确的Logger原型链,你写的自定义log方法根本不在实例的原型查找路径上。
  • 实例方法遮蔽:Winston 3.x 初始化Logger实例时,会把info/warn/error/debug等所有等级的日志方法直接挂载到实例本身,且这些方法内部持有的是初始化阶段的原始log方法引用,不会动态去原型链上查找你重写的版本,加上实例自身属性的查找优先级高于原型属性,你写在子类上的log方法会被直接遮蔽,永远不会触发。

另外你原有代码的参数透传也有问题:super.log(args)没有展开参数,会把所有入参打包成单个数组传给内置方法,导致日志格式异常。

正确实现

推荐方案:实例拦截(无侵入、兼容性最好)

不需要自定义类,直接在工厂函数生成实例后劫持log方法即可,适配所有Winston3的小版本:

const winston = require('winston');

function buildCustomLogger(options) {
  const logger = winston.createLogger(options);
  // 缓存原始log方法的绑定引用
  const baseLog = logger.log.bind(logger);

  // 重写实例自身的log方法
  logger.log = (...logArgs) => {
    // 此处编写你的前置逻辑
    const [level, message, ...meta] = logArgs;
    console.log(`[自定义前置处理] 准备输出${level}等级日志:${message}`);

    // 执行原始日志逻辑
    return baseLog(...logArgs);
  };

  // 重新绑定各等级日志方法,让它们指向新的log方法
  Object.keys(logger.levels).forEach(level => {
    logger[level] = (...args) => logger.log(level, ...args);
  });

  return logger;
}

// 调用示例
const logger = buildCustomLogger({
  level: 'debug',
  transports: [new winston.transports.Console()]
});
logger.info('服务启动成功', { port: 3000 });

ES6 Class 实现方案

如果必须使用Class写法,要继承Winston内部暴露的Logger基类,不要继承createLogger工厂函数:

const winston = require('winston');
// 引入真正的Logger构造类
const WinstonLogger = require('winston/lib/winston/logger').Logger;

class CustomLogger extends WinstonLogger {
  constructor(options) {
    super(options);
    const baseLog = this.log.bind(this);

    // 重写实例自身的log方法,不要重写原型方法
    this.log = (...logArgs) => {
      // 前置逻辑
      console.log('[Class实现] 自定义前置逻辑触发');
      return baseLog(...logArgs);
    };

    // 重绑定等级方法
    Object.keys(this.levels).forEach(level => {
      this[level] = (...args) => this.log(level, ...args);
    });
  }
}

// 调用示例,注意要直接new实例,不要调用createLogger
const logger = new CustomLogger({
  level: 'info',
  transports: [new winston.transports.Console()]
});
logger.warn('内存占用超过阈值', { usage: '85%' });

注意:不要尝试直接重写Logger原型上的log方法,会污染所有Winston实例,且如果项目中多个地方自定义日志逻辑会互相冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 07:06:24