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

Posted

技术标签:

【中文标题】如何使用 Winston 3 记录完整的堆栈跟踪?【英文标题】:How to Log Full Stack Trace with Winston 3? 【发布时间】:2018-04-24 04:59:21 【问题描述】:

我的记录器设置如下:

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,结果显示为未定义。

谢谢!

【问题讨论】:

【参考方案1】:

您可以编写一个格式化程序将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 ......" 

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

【讨论】:

什么是myFormat 如果我们需要记录一条消息,然后是一个错误(类似于 Java 的 log4j 等):logger.error('Failed to do sth', e)【参考方案2】:

2021 年 1 月 14 日更新 - 这不再适用于新版本的 Winston。

原答案

@Ming 的回答让我部分明白了,但是要对错误进行字符串描述,这就是我在我们的问题上进行完整堆栈跟踪的方式:

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 ...

【讨论】:

我注意到这是可行的,但是文档在哪里说需要将错误对象放在第二个参数中? @5413668060 您不应该将错误对象放在第二个参数中。那是给meta data的。如果您将错误对象作为第一个参数传递,那么您必须将errorStackTracerFormat 函数中的info.meta.XXX 引用更改为info.XXX 抱歉,您的示例并没有做到它声称的那样。 是的,info 对象的 console.dir 不显示任何元数据。相反,它显示了一些 splat 符号。内部肯定发生了变化。【参考方案3】:

这是我的logger.jswinston": "^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;

【讨论】:

【参考方案4】:

对于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

【讨论】:

【参考方案5】:

这是我的记录器配置。添加了errors( stack: true ),感谢Murli Prajapati ans 和printf 函数中的小技巧。我的温斯顿版本是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));

【讨论】:

【参考方案6】:

这是 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`;
              ),
            )
  ));

【讨论】:

请注意:The prettyPrint format should not be used in production because it may impact performance negatively and block the event loop.github.com/winstonjs/logform#prettyprint

以上是关于如何使用 Winston 3 记录完整的堆栈跟踪?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Monolog 记录完整的堆栈跟踪

如何在 Cloudera 中查看完整的异常/错误堆栈跟踪

如何记录 Python 3 异常,但没有其堆栈跟踪?

使用 sbt 和 testng 时,如何获取测试中抛出的异常的完整堆栈跟踪?

如何避免记录来自 Java 异常的敏感信息?

如何从 winston@3 记录器输出中删除 [符号] 字段?