迁移至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
相关产品推荐
相关产品推荐

