在重新抛出的错误中合并堆栈跟踪

问题描述 投票:0回答:3

我在这里重新抛出一个来自 Sequelize promise (Bluebird) 的错误。首先,这样做是为了更改错误消息,但正如它所显示的那样,这也会产生更多信息的堆栈跟踪。

有点像

sequelize.sync().catch(originalError => {
  const rethrownError = new Error(originalError.msg + ': ' + originalError.sql);
  throw rethrownError;
});

其中

originalError.stack
不包含导致错误的行,但它包含重要信息,它源自 Sequelize 和 MySQL 驱动程序:

SequelizeDatabaseError: ER_KEY_COLUMN_DOES_NOT_EXITS: Key column 'NonExisting' doesn't exist in table
    at Query.formatError (...\node_modules\sequelize\lib\dialects\mysql\query.js:175:14)
    at Query._callback (...\node_modules\sequelize\lib\dialects\mysql\query.js:49:21)
    at Query.Sequence.end (...\node_modules\mysql\lib\protocol\sequences\Sequence.js:85:24)
    at Query.ErrorPacket (...\node_modules\mysql\lib\protocol\sequences\Query.js:94:8)
    at Protocol._parsePacket (...\node_modules\mysql\lib\protocol\Protocol.js:280:23)
    at Parser.write (...\node_modules\mysql\lib\protocol\Parser.js:74:12)
    at Protocol.write (...\node_modules\mysql\lib\protocol\Protocol.js:39:16)
    at Socket.<anonymous> (...\node_modules\mysql\lib\Connection.js:109:28)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)
    at TCP.onread (net.js:548:20)

rethrownError.stack
包含兴趣点(堆栈中的第一行),但其他一切都是垃圾:

Error: ER_KEY_COLUMN_DOES_NOT_EXITS: Key column 'NonExisting' doesn't exist in table
    at sequelize.sync.catch (...\app.js:59:17)
    at tryCatcher (...\node_modules\bluebird\js\release\util.js:16:23)
    at Promise._settlePromiseFromHandler (...\node_modules\bluebird\js\release\promise.js:504:31)
    at Promise._settlePromise (...\node_modules\bluebird\js\release\promise.js:561:18)
    at Promise._settlePromise0 (...\node_modules\bluebird\js\release\promise.js:606:10)
    at Promise._settlePromises (...\node_modules\bluebird\js\release\promise.js:681:18)
    at Async._drainQueue (...\node_modules\bluebird\js\release\async.js:138:16)
    at Async._drainQueues (...\node_modules\bluebird\js\release\async.js:148:10)
    at Immediate.Async.drainQueues (...\node_modules\bluebird\js\release\async.js:17:14)
    at runCallback (timers.js:637:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)

我想保留关于它们的信息 - 并指定它们之间的链接,而不仅仅是添加为两个不相关的日志条目。

我一直在考虑将它们记录为带有串联堆栈的单个错误,

rethrownError.stack += '\n' + originalError.stack

这两个错误应该如何处理?他们的堆栈跟踪应该加入吗?在 JavaScript(尤其是 Node.js)中是否有合并错误堆栈的约定?

目的是使产生的错误有意义,并且不扰乱现有的解析错误堆栈跟踪的工具(即 Stacktrace.js)。

正在考虑的项目使用 Winston 记录器或普通

console.error
,因此错误在某些时候被字符串化(在上面的示例中,它是通过未处理的拒绝处理程序记录的)。

javascript node.js sequelize.js stack-trace winston
3个回答
11
投票

🚨 2022 年更新:

Error.prototype.cause
已在 ES2022 中实施。考虑使用本机实现。

自 ECMAScript 2022 起,新的 Error() 允许我们指定导致它的原因:

try {
  // ···
} catch (error) {
  throw new Error(
    `While processing ${filePath}`,
    {
      cause: error
    }
  );
}

另见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause


原答案:

这里是 VError 的轻量级替代品:rerror (我是作者)

思路是一样的:在错误中包装错误。然而,它要简单得多。它的功能较少,但也适用于浏览器。它还考虑到创建堆栈跟踪的成本很高。它不是创建堆栈跟踪并将它们附加到字符串,而是在内部创建一堆错误,并且只在需要时创建大堆栈跟踪(使用 getter)。

例子

function fail() {
  throw new RError({
    name: 'BAR',
    message: 'I messed up.'
  })
}

function failFurther() {
  try {
    fail()
  } catch (err) {
    throw new RError({
      name: 'FOO',
      message: 'Something went wrong.',
      cause: err
    })
  }
}

try {
  failFurther()
} catch (err) {
  console.error(err.why)
  console.error(err.stacks)
}

输出

FOO: Something went wrong. <- BAR: I messed up.
Error
    at failFurther (/Users/boris/Workspace/playground/es5/index.js:98:11)
    at Object.<anonymous> (/Users/boris/Workspace/playground/es5/index.js:107:3)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.runMain (module.js:590:10)
    at run (bootstrap_node.js:394:7)
<- Error
    at fail (/Users/boris/Workspace/playground/es5/index.js:88:9)
    at failFurther (/Users/boris/Workspace/playground/es5/index.js:96:5)
    at Object.<anonymous> (/Users/boris/Workspace/playground/es5/index.js:107:3)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.runMain (module.js:590:10)

推荐阅读:https://www.joyent.com/node-js/production/design/errors


7
投票

据我所知,在 Node.js 中没有内置的方法来处理嵌套错误。我唯一可以推荐你的是使用 VError 库。它在处理高级错误处理时非常有用。

您可以使用

fullStack
组合许多错误的堆栈跟踪:

var err1 = new VError('something bad happened');
var err2 = new VError(err1, 'something really bad happened here');

console.log(VError.fullStack(err2));

1
投票

基于https://stackoverflow.com/a/42147148/1703845,我抽象了

VError.fullStack
这样的调用

class FullStackVError extends VError {
  constructor(cause, ...args) {
    super(cause, ...args);

    let childFullStack;

    if (cause instanceof VError) {
      childFullStack = cause.stack;
      cause.stack = cause._originalStack;
    }

    this._originalStack = this.stack;
    this.stack = VError.fullStack(this);

    if (cause instanceof VError) {
      cause.stack = childFullStack;
    }
  }
}

现在

console.log(err2.stack);
相当于
console.log(VError.fullStack(err2));
本来的样子。

© www.soinside.com 2019 - 2024. All rights reserved.