如何配置Winston日志实现不同级别消息写入对应日志文件
问题诱因
- Winston默认使用npm风格的日志级别规则,级别优先级和对应数值为:
error(0) > warn(1) > info(2) > http(3) > verbose(4) > debug(5) > silly(6),数值越小代表日志优先级越高。 - 你在transport中配置的
level参数,作用是设置当前日志输出通道可接收的最低优先级阈值,而非“仅接收该级别日志”:所有优先级高于或等于该阈值的日志,都会被输出到对应通道。举个例子:你给info.log设置level: 'info',对应阈值数值为2,那么所有优先级数值≤2的日志(error、warn、info)都会被写入info.log,这就是error日志混入info.log、error日志混入warn.log的核心原因。 - 你观察到的“仅初次执行npm start时error写入info.log、其余场景无异常”属于感知偏差:只要触发error级别日志,它就会满足info.log、warn.log、debug.log的阈值规则,被同步写入这几个文件,其余场景未出现只是因为你没有触发对应级别的日志,或是未注意到文件的追加写入内容。
- debug.log同时写入error、debug级别日志也是相同规则导致:debug级别对应阈值数值为5,error优先级远高于该阈值,自然会被写入debug.log。warn.log中混入info日志,一般是级别阈值规则叠加日志追加写入的历史内容导致,添加精确过滤后即可解决。
正确配置方法
要实现单一级别日志单独写入对应文件的分流效果,不能仅依赖level参数配置,需要给每个文件输出通道添加单独的级别过滤规则,仅放行级别完全匹配的日志。Winston支持在format中返回false直接过滤掉不符合规则的日志,修正后的完整配置代码如下:
const { createLogger, transports, format } = require('winston'); const { combine, timestamp, printf } = format; const customFormat = printf(({ level, message, timestamp }) => { if (!message.includes('&')) { return `${timestamp} ${level}: ${message}`; } else { return `${timestamp} - ${message.split('&')[0]} - ${level}: ${message.split('&')[1]}`; } }); // 生成对应级别的过滤format const levelFilter = (targetLevel) => format((info) => { return info.level === targetLevel ? info : false; })(); const logger = createLogger({ format: combine( timestamp(), customFormat ), transports: [ new transports.File({ filename: `${__dirname}/log/error.log`, level: 'error', format: combine(levelFilter('error'), timestamp(), customFormat) }), new transports.File({ filename: `${__dirname}/log/info.log`, level: 'info', format: combine(levelFilter('info'), timestamp(), customFormat) }), new transports.File({ filename: `${__dirname}/log/warn.log`, level: 'warn', format: combine(levelFilter('warn'), timestamp(), customFormat) }), new transports.File({ filename: `${__dirname}/log/debug.log`, level: 'debug', format: combine(levelFilter('debug'), timestamp(), customFormat) }), // 控制台保留全量日志输出,不需要过滤 new transports.Console({ timestamp: true, format: combine(timestamp(), customFormat) }), ], exceptionHandlers: [ new transports.Console({ json: false, timestamp: true }), new transports.File({ filename: `${__dirname}/log/exceptions.log`, json: false }) ], exitOnError: false }); module.exports = logger;
配置说明:
- 封装了通用的
levelFilter方法,传入目标级别即可生成对应的过滤规则,只有日志级别和目标级别完全一致时才会被放行 - 每个文件传输通道单独引入对应级别的过滤器,同时保留定义的时间戳和自定义输出格式
- 控制台通道不添加过滤,保留全级别日志输出方便开发调试
- 配置完成后建议先清空原有log目录下的历史日志文件,再重新启动项目验证分流效果,避免旧日志内容干扰判断
内容的提问来源于stack exchange,提问作者Anetta Dominic
相关产品推荐
相关产品推荐

