如何在node.js中使用堆栈跟踪console.log发生错误?

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

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

但我仍然不明白为什么我的日志不显示此错误的跟踪信息。 在我的代码中返回错误的任何地方,我都将其登录到控制台:

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)...ð噢。 我这样做是通过筛选出以____at开始的____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)来打印完整的堆栈。

链接地址: http://www.djcxy.com/p/82467.html

上一篇: How to console.log an error with stack trace in node.js?

下一篇: Converting an object to a string