繁体   English   中英

如何在node.js中使用stack trace记录错误?

[英]How to console.log an error with stack trace in node.js?

我一直在尝试调试我的节点应用程序,以便在我的日志中找到错误的来源,该错误仅显示为“ Error: Can't set headers after they are sent ”,没有跟踪信息或任何上下文。

碰巧,我想我现在已经解决了这个问题...我正在使用connect-timeout并且我正在继续处理传递给异步网络操作的回调,尽管回调最终会尝试执行res.send() ,尽管在网络操作期间, connect-timeout req.timedout设置为“true”。

但我仍然无法理解为什么我的日志没有显示此错误的跟踪信息。 在我的代码中返回错误的任何地方我将其记录到控制台:

console.log(err);

如果err对象中有可用的跟踪信息,并且这似乎放在err.stack ,那么上述语句是否应该将err (包括err.stack )的全部内容转储到控制台日志中? 我的理解是,通过上述操作,我不会丢失任何信息,例如:

console.log(err.stack);

但是像这样的帖子似乎暗示了其他情况(虽然链接的帖子现在已经更新)。

我实际上更进一步,并添加一些相关的文本,以帮助找到错误:

console.log('error in dodgyFunction:', err);

但尽管如此,我仍然只得到“ Error: Can't set headers after they are sent ”,没有任何上下文我会说。 这是因为此控制台错误消息是在外部库(如express )中输出的吗? 我认为外部库应该将错误发送回主代码进行相应的处理?

编辑:这是我将错误和超时检查放在传递给异步操作的回调函数顶部的示例:

var execFile = require('child_process').execFile;
execFile('dodgycommand', options, function(error, stdout, stderr) {
    if (req.timedout) {
        console.log('timeout detected whilst running dodgycommand, so aborting...');
        return;
    }
    if (error) {
        console.log('error running dodgycommand:', error);
        res.sendStatus(400);
        return;
    }

    // ... it's safe to continue ...

}

我基本上都遵循相同的模式。

我刚刚弄清楚发生了什么,我希望这会帮助其他人避免这个初学者的错误。

对于我的一些错误记录,我使用类似下面的内容,使用字符串连接来构造错误消息:

console.log('error in function abc: ' + err + ' whilst doing xyz');

而在其他地方,我使用类似下面的内容,只是将错误消息的各个部分作为单独的参数传递给console.log

console.log('error in function xyz:', err, 'whilst doing abc');

我现在看到这些给出了不同的结果!

前者必须将err字符串化,以便它可以与消息的其他部分连接,并且根据这一点 ,这样做它只使用消息部分。

但是,在后一种形式中, err对象必须由console.log处理,并且作为一个整体进行转储。

这就解释了为什么我有时没有看到错误的全部内容,正如我所期待的那样,有时我也是如此。

对于由其他库放置的控制台日志消息,要检查的其他内容是您没有过滤掉日志查看器中日志消息的“堆栈”部分...原来我 (为了节省日志配额......我正在使用papertrail)... d'oh。 我这样做是通过过滤掉以____at开头的任何行(四个空格后跟'at'),例如____at Request.self.callback

你的模式看起来很普遍,不过我会说通常我不喜欢它,更多的是在一秒钟内。

至于你的主要问题,根据你提供的内容很难回答它。 如果您显示实际代码而不是“我通常遵循此模式”,它可能会有所帮助。 但同样可能的是,错误被抛出到你没想到的地方,所以你的console.log根本没有被调用。

看起来你正在寻找最佳实践,所以我会告诉你我认为迄今为止我发现的最好的东西。

首先,不要使用console.log进行日志记录。 这并不可怕,但你可以做得更好,更好。 我最喜欢的是使用morgan作为中间件来记录请求信息,并调试应用程序日志记录。

通过debug您可以设置自定义日志级别,并以您想要的任何粒度级别收听您想要的任何级别。 它都是通过设置DEBUG环境变量来控制的,在生产中你可以重定向到文件或你想要的任何其他目的地。 此外,许多节点模块(包括Express和Connect)使用Debug作为其记录器,因此通过调整DEBUG变量,您可以根据需要查看内部日志记录的多少。 对于弄清楚哪里出了问题非常有用。

其次,正如我所说,在路由方面,我根本不使用你所拥有的模式。 如果我不小心的话,我发现很容易意外地多次发送标题,所以我的中间件总是返回next()并且响应只在实际的处理程序中发送,我只能确保只触发一次。 当涉及到错误时,我总是传递next(e) ,然后我可以在错误处理函数中处理它。 我还创建了praeter库,以根据Web状态代码和通用错误处理程序提供标准错误。

模式看起来像这样:

// middleware function to put something on the request object
app.use((req, res, next) => {
  MyModel.doSomething((e, thing) => {
    if (e) return next(e);
    if (!thing) return next(new NotFound()); // NotFound is an error in praeter that equates to a 404. 
    req.thing = thing;
    return next();
  });
});

然后

// log in here is a reference to my debug configured log object
app.use((err, req, res, next) => {
  log.error(err);
  log.error(err.stack);
  return res.status(err.statusCode || 500).send(err.message)
});

请注意,这是最终错误处理程序的简单示例。 我经常有几个这样的地方,根据应用需求,我可能会以不同的方式处理不同的错误代码。

我现在安装了n ,我可以确认以下内容:

节点4.0.0

使用console.log(err)仅打印错误消息。

节点7.7.0 (最新)

使用console.log(err)打印错误消息和完整堆栈。


我已经确认在6.0.0版本上此行为已更改。 因此,如果您使用旧版本,我建议您更新Node.js或使用console.log(err.stack)来打印完整堆栈。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM