使用winston-daily-rotate-file实现Winston JSON日志格式化遇阻求助
解决Winston Daily Rotate File输出JSON日志的问题
我懂你的痛点——想让Winston把日志输出成JSON格式,但用了winston-daily-rotate-file这个轮转插件后,常规的JSON配置好像没起作用。咱们直接调整你的代码来搞定这个问题:
修改后的完整代码
const path = require('path'); const { createLogger, format, transports, addColors } = require('winston'); const winstonDailyRotateFile = require('winston-daily-rotate-file'); const { combine, timestamp, json, colorize, label, printf, errors, align } = format; const CustomTransport = require('./customtransport') const customLevels = { levels: { error: 0, warn: 1, fileProcessed: 2, info: 3, debug: 4, silly: 5, }, colors: { error: 'bold red', warn: 'bold yellow', fileProcessed: 'bold blue', info: 'bold cyan', debug: 'bold gray', silly: 'bold magenta' } }; addColors(customLevels.colors); const consoleFormat = printf(({ level, message, label, stack, timestamp }) => { const log = `${timestamp} ${level}: [${label}] ${message}`; return stack ? `${log}\n${stack}` : log; }); module.exports = (module) => { const logger = createLogger({ levels: customLevels.levels, level: 'silly', // 全局开启最低级别日志,确保所有日志都能被捕获 format: combine( errors({ stack: true }), // 优先捕获错误栈,保证后续格式能处理 label({ label: path.basename(module.filename) }), timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // 把Winston内部的级别数字转换回自定义级别名称 format((info) => { info.level = Object.keys(customLevels.levels).find(key => customLevels.levels[key] === info.level) || info.level; return info; })() ), transports: [ new CustomTransport({ }), new winstonDailyRotateFile({ // 只需要指定JSON格式,通用字段已在全局format处理 format: json(), dirname: './logs', filename: 'sppa-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true, maxSize: '20m', maxFiles: '14d' }) ] }); // 开发环境控制台输出 if (process.env.NODE_ENV !== 'production') { logger.add(new transports.Console({ levels: customLevels.levels, level: 'silly', format: combine( colorize(), align(), errors({ stack: true }), label({ label: path.basename(module.filename) }), timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), consoleFormat ), })); } return logger; }
关键修改说明
- 全局Format复用:把错误栈捕获、label、时间戳这些通用逻辑放到
createLogger的全局format里,这样所有传输器(包括你的自定义传输和轮转文件传输)都会自动应用这些处理,避免重复配置。 - 自定义级别名称修复:Winston内部会把级别转换成数字存储,所以加了一个自定义格式化函数,把数字转回到你定义的级别名称(比如
fileProcessed),这样JSON日志里的level字段会显示正确的名称而不是数字。 - 错误栈序列化:确保
errors({ stack: true })在format组合的最前面,这样所有错误的栈信息都会被捕获并添加到日志对象中,最终被json()格式序列化为JSON的一部分。 - 全局级别设置:在
createLogger里设置level: 'silly',确保所有级别的日志都能被捕获,后续传输器可以根据需求调整级别(如果需要的话)。
效果验证
当你调用类似logger.fileProcessed('用户上传文件已处理')或者logger.error(new Error('数据库连接失败'))时,日志文件里会输出标准的JSON格式:
{"level":"fileProcessed","message":"用户上传文件已处理","label":"upload.js","timestamp":"2024-05-20 16:45:30"}
错误日志会包含完整栈信息:
{"level":"error","message":"数据库连接失败","stack":"Error: 数据库连接失败\n at connectDB (/path/to/upload.js:25:15)\n ...","label":"upload.js","timestamp":"2024-05-20 16:45:30"}
内容的提问来源于stack exchange,提问作者naitunix




