You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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;
}

关键修改说明

  1. 全局Format复用:把错误栈捕获、label、时间戳这些通用逻辑放到createLogger的全局format里,这样所有传输器(包括你的自定义传输和轮转文件传输)都会自动应用这些处理,避免重复配置。
  2. 自定义级别名称修复:Winston内部会把级别转换成数字存储,所以加了一个自定义格式化函数,把数字转回到你定义的级别名称(比如fileProcessed),这样JSON日志里的level字段会显示正确的名称而不是数字。
  3. 错误栈序列化:确保errors({ stack: true })在format组合的最前面,这样所有错误的栈信息都会被捕获并添加到日志对象中,最终被json()格式序列化为JSON的一部分。
  4. 全局级别设置:在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

火山引擎 最新活动