如何使用Winston 3记录完整的堆栈跟踪?

61

我的记录器设置如下:

const myFormat = printf(info => {
   return `${info.timestamp}: ${info.level}: ${info.message}: ${info.err}`;
 });


 const logger =
   winston.createLogger({
   level: "info",
   format: combine(timestamp(), myFormat),

   transports: [
     new winston.transports.File({
     filename:
      "./logger/error.log",
        level: "error"
    }),
     new winston.transports.File({
       filename:
       "./logger/info.log",
       level: "info"
   })
  ]
})

然后我记录了这样的错误:

logger.error(`GET on /history`, { err });

如何通过错误传输记录完整的堆栈跟踪?我尝试传递err.stack,但是输出为undefined。

谢谢!

7个回答

43

对于winston版本3.2.0+,以下内容将在日志输出中添加堆栈跟踪:

import { createLogger, format, transports } from 'winston';

const { combine, timestamp, prettyPrint, colorize, errors,  } = format;


const logger = createLogger({
  format: combine(
    errors({ stack: true }), // <-- use errors format
    colorize(),
    timestamp(),
    prettyPrint()
  ),
  transports: [new transports.Console()],
});  

参考:https://github.com/winstonjs/winston/issues/1338#issuecomment-482784056


如果您正在使用TypeScript,请用winston.format代替= format。 - Ricardo Mayerhofer
2
winston 正在控制台中使用 JSON,因此 colorize() 就像 level: '\x1B[31merror\x1B[39m' 一样啦!哈哈 - TeaDrinker

21

您可以编写一个格式化程序将 error.stack 传递给日志记录。

const errorStackFormat = winston.format(info => {
  if (info instanceof Error) {
    return Object.assign({}, info, {
      stack: info.stack,
      message: info.message
    })
  }
  return info
})

const logger = winston.createLogger({
  transports: [ ... ],
  format: winston.format.combine(errorStackFormat(), myFormat)
})

logger.info(new Error('yo')) // => {message: 'yo', stack: "Error blut at xxx.js:xx ......"} 

(输出结果将取决于您的配置)


1
myFormat是什么? - CodyBugstein
1
如果我们需要记录一条消息,后面跟着一个错误(类似于Java的log4j等):logger.error('Failed to do sth', e),该怎么办? - Janaka Bandara

13

这里是 Winston 3.2 的另一种方式。

现在的 Winston 带有内置的堆栈跟踪格式化程序,但是如果相同的格式化程序与 winston.format.simple() 结合使用似乎不会触发。因此,您需要使用 winston.format.printf,如 Kirai Mali 的回答所述。我无法弄清楚如何在相同的配置中同时配置 winston.format.errors()winston.format.simple()

基于当前的 Winston README 示例和上面的答案,这是我的配置,它使用 JSON 格式的日志文件,但对于本地开发控制台,它仍然提供彩色的日志行和良好的堆栈跟踪。


// Use JSON logging for log files
// Here winston.format.errors() just seem to work
// because there is no winston.format.simple()
const jsonLogFileFormat = winston.format.combine(
  winston.format.errors({ stack: true }),
  winston.format.timestamp(),
  winston.format.prettyPrint(),
);

// Create file loggers
const logger = winston.createLogger({
  level: 'debug',
  format: jsonLogFileFormat,
  transports: [
    //
    // - Write to all logs with level `info` and below to `combined.log`
    // - Write all logs error (and below) to `error.log`.
    //
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ],
  expressFormat: true,
});

// When running locally, write everything to the console
// with proper stacktraces enabled
if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format:  winston.format.combine(
                winston.format.errors({ stack: true }),
                winston.format.colorize(),
                winston.format.printf(({ level, message, timestamp, stack }) => {
                  if (stack) {
                      // print log trace
                      return `${timestamp} ${level}: ${message} - ${stack}`;
                  }
                  return `${timestamp} ${level}: ${message}`;
              }),
            )
  }));
}

3
请注意:prettyPrint 格式不应在生产环境中使用,因为它可能会对性能产生负面影响并阻塞事件循环。https://github.com/winstonjs/logform#prettyprint - vanduc1102

12

更新于 2021年1月14日 - 这种方法在较新版本的Winston中已不再适用。

原回答

@明的回答让我有所启发,但为了在错误信息中获得字符串描述,这是我在我们公司实现完整堆栈跟踪的方法:

import winston from "winston";

const errorStackTracerFormat = winston.format(info => {
    if (info.meta && info.meta instanceof Error) {
        info.message = `${info.message} ${info.meta.stack}`;
    }
    return info;
});

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.splat(), // Necessary to produce the 'meta' property
        errorStackTracerFormat(),
        winston.format.simple()
    )
});

logger.error("Does this work?", new Error("Yup!"));

// The log output:
//   error: Does this work? Error: Yup!
//       at Object.<anonymous> (/path/to/file.ts:18:33)
//       at ...
//       at ...

1
我注意到这是工作,但是哪里有文档说明需要将Error对象放在第二个参数中? - 5413668060
1
@5413668060 你不应该把错误对象放在第二个参数中。那是用于元数据的。如果你将错误对象作为第一个参数传递,那么你需要将errorStackTracerFormat函数中的info.meta.XXX引用更改为info.XXX - isick
5
抱歉,但是你的例子并没有达到其所声称的功能。 - Yuki
1
是的,info对象的console.dir不显示任何元数据。它只显示一些星号符号。内部必须已经改变了。 - siride

7

这是我的日志记录器配置。感谢Murli Prajapati ans的建议,我添加了errors({ stack: true }), 并在printf函数中使用小技巧。我的winston版本是3.2.1

const {format, transports} = require('winston');
const { timestamp, colorize, printf, errors } = format;
const { Console, File } = transports;
LoggerConfig = {
        level: process.env.LOGGER_LEVEL || 'debug',
        transports: [
            new Console(),
            new File({filename: 'application.log'})
        ],
        format: format.combine(
            errors({ stack: true }),
            timestamp(),
            colorize(),
            printf(({ level, message, timestamp, stack }) => {
                if (stack) {
                    // print log trace 
                    return `${timestamp} ${level}: ${message} - ${stack}`;
                }
                return `${timestamp} ${level}: ${message}`;
            }),
        ),
        expressFormat: true, // Use the default Express/morgan request formatting. Enabling this will override any msg if true. Will only output colors with colorize set to true
        colorize: false, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
        ignoreRoute: function (req, res) {
            return false;
        } // optional: allows to skip some log messages based on request and/or response
}

我正在使用相同的配置在express-winston和一般日志中。
const winston = require('winston');
const expressWinston = require('express-winston');

/**
 * winston.Logger
 * logger for specified log message like console.log
 */
global.__logger = winston.createLogger(LoggerConfig);
/**
 * logger for every HTTP request comes to app
 */
app.use(expressWinston.logger(LoggerConfig));


不错。它只打印与API相关的信息,而且是在执行API之后。如何更改中间件的优先级? - Pranu Pranav

4

这是我的 logger.js 文件,使用了 winston": "^3.1.0 模块。

const { createLogger, format, transports } = require('winston');
const { combine, timestamp, printf, colorize, splat } = format;

const myFormat = printf((info) => {
  if (info.meta && info.meta instanceof Error) {
    return `${info.timestamp} ${info.level} ${info.message} : ${info.meta.stack}`;
  }
  return `${info.timestamp} ${info.level}: ${info.message}`;
});

const LOG_LEVEL = process.env.LOG_LEVEL || 'debug';
const logger = createLogger({
  transports: [
    new (transports.Console)(
      {
        level: LOG_LEVEL,
        format: combine(
          colorize(),
          timestamp(),
          splat(),
          myFormat
        )
      }
    )
  ]
});
module.exports = logger;

0

为了使用winston获取堆栈跟踪,我必须使用以下记录器:

 winston.createLogger({
    level: 'debug',
    format: winston.format.combine(
      winston.format.errors({ stack: true }),
      winston.format.metadata(),
    ),
    transports: new winston.transports.Console(),
  }),

然后你可以添加以下内容使其看起来更好:

      winston.format.timestamp(),
      winston.format.prettyPrint(),


注意,对我来说仅仅添加format.errors是不够的,我还需要format.metadata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接