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