在NodeJS中重新抛出exception,不会丢失堆栈跟踪

如何在nodejs / javascript中重新引发错误或exception,并包含自定义消息。

我有以下代码

var json = JSON.parse(result); 

而且我想在发生任何分析错误时将result内容包含在exception消息中。 像这样的东西。

 1. try { 2. var json = JSON.parse(result); 3. expect(json.messages.length).to.be(1); 4. } catch(ex) { 5. throw new Error(ex.message + ". " + "JSON response: " + result); 6. } 

这里的问题是我失去了我的堆栈跟踪。

有没有办法做到这一点类似于java

 throw new Error("JSON response: " + result, ex); 

我不知道像Java的本地方法,我还没有find一个优雅的解决scheme。

创buildnew Error的问题是,您可能会丢失所引发的错误(包括堆栈和types)的任何元数据。

修改现有的错误更快,但是仍然可以修改数据,并且在其他地方创build错误的时候感觉不对。

新的错误,新的堆栈

Node.js中的错误的.stack属性可以修改,以便在抛出之前说出您喜欢的内容。

完全replace错误堆栈可能会使debugging变得困惑。 当抛出的原始错误和error handling程序位于不同的位置或文件中时。 您可能能够跟踪原始错误的来源,但不能跟踪实际被困的处理程序。 为了避免这种情况,最好保留一些对这两个错误的引用。 如果存在元数据,也可以访问完整的原始错误。

 try { throw new Error('First one') } catch (error) { let e = new Error(`Rethrowing the "${error.message}" error`) e.original = error e.stack = e.stack.split('\n').slice(0,2).join('\n') + '\n' + error.stack throw e } 

抛出:

 /so/42754270/test.js:9 throw e ^ Error: Rethrowing the "First one" error at test (/so/42754270/test.js:5:13) Error: First one at test (/so/42754270/test.js:3:11) at Object.<anonymous> (/so/42754270/test.js:13:1) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.runMain (module.js:604:10) at run (bootstrap_node.js:394:7) at startup (bootstrap_node.js:149:9) 

所以我们创build了一个新的通用错误。 不幸的是,原始错误的types变得隐藏,但是错误已经被附加为.original ,以至于仍然可以被访问。 除了重要的生成线和附加的原始错误堆栈之外,新的堆栈已经被大量移除。

任何尝试parsing堆栈跟踪的工具可能无法用于此更改或最佳情况,检测到两个错误。

ES2015错误类别

把它变成一个可重用的ES2015 +错误类…

 // Standard error extender from @deployable/errors class ExtendedError extends Error { constructor(message){ super(message) this.name = this.constructor.name this.message = message if (typeof Error.captureStackTrace === 'function'){ Error.captureStackTrace(this, this.constructor) } else { this.stack = (new Error(message)).stack } } } class RethrownError extends ExtendedError { constructor(message, error){ super(message) if (!error) throw new Error('RethrownError requires a message and error') this.original = error this.new_stack = this.stack let message_lines = (this.message.match(/\n/g)||[]).length + 1 this.stack = this.stack.split('\n').slice(0, message_lines+1).join('\n') + '\n' + error.stack } } throw new RethrownError(`Oh no a "${error.message}" error`, error) 

结果是

 /so/42754270/test2.js:31 throw new RethrownError(`Oh no a "${error.message}"" error`, error) ^ RethrownError: Oh no a "First one" error at test (/so/42754270/test2.js:31:11) Error: First one at test (/so/42754270/test2.js:29:11) at Object.<anonymous> (/so/42754270/test2.js:35:1) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.runMain (module.js:604:10) at run (bootstrap_node.js:394:7) at startup (bootstrap_node.js:149:9) 

那么你知道,每当你看到一个RethrownError原始错误仍然可以在.original

这个方法并不完美,但是这意味着我可以从底层模块重新input已知的错误到更容易处理的genericstypes中,通常使用蓝filtered过滤.catch(TypeError, handler)

同样的错误,修改堆栈

有些时候,你将需要保持原来的错误大部分是原样的。

在这种情况下,你可以追加/插入新的信息到现有的堆栈上。

 file = '/home/jim/plumbers' try { JSON.parse('k') } catch (e) { let message = `JSON parse error in ${file}` let stack = new Error(message).stack e.stack = e.stack + '\nFrom previous ' + stack.split('\n').slice(0,2).join('\n') + '\n' throw e } 

哪个返回

 /so/42754270/throw_error_replace_stack.js:13 throw e ^ SyntaxError: Unexpected token k in JSON at position 0 at Object.parse (native) at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:8:13) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.runMain (module.js:604:10) at run (bootstrap_node.js:394:7) at startup (bootstrap_node.js:149:9) From previous Error: JSON parse error in "/home/jim/plumbers" at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:11:20) 

如果你想要做的只是改变信息,你可以改变信息:

 try { throw new Error("Original Error"); } catch(err) { err.message = "Here is some context -- " + err.message; throw err; } 

你也可以继续抛出你的尝试链的错误。 如果你想修改任何东西:在b中的throw语句之前。

 function a() { throw new Error('my message'); } function b() { try { a(); } catch (e) { // add / modify properties here throw e; } } function c() { try { b(); } catch (e) { console.log(e); document.getElementById('logger').innerHTML = e.stack; } } c(); 
 <pre id="logger"></pre>