如何在抛出错误时减少堆栈跟踪(点调用站点)

How to reduce stack trace when throwing error (point to call site)

本文关键字:跟踪 堆栈 调用 站点 出错 错误      更新时间:2023-09-26

我有一个这样的函数:

function foo() {
  throw new Error('`foo` has been removed in favor of `bar`')
}

当有人调用foo时,我希望堆栈跟踪(错误输出)指向foo的调用位置,而不是foo内部的throw行。

例如,我得到这个:

$ node test.js
/home/ubuntu/tmp/test.js:2
  throw new Error('`foo` has been removed in favor of `bar`')
        ^
Error: `foo` has been removed in favor of `bar`
    at foo (/home/ubuntu/tmp/test.js:2:9)
    at Object.<anonymous> (/home/ubuntu/tmp/test.js:5:1)
    ...

我怎么得到这个呢?

$ node test.js
/home/ubuntu/tmp/test.js:5
  foo()
  ^
Error: `foo` has been removed in favor of `bar`
    at Object.<anonymous> (/home/ubuntu/tmp/test.js:5:1)
    ...

步骤1:定义一个自定义的Error对象。查看更多信息:A String is not an Error.

function CustomError (msg) {
  Error.call(this);
  // By default, V8 limits the stack trace size to 10 frames.
  Error.stackTraceLimit = 10;
  // Customizing stack traces
  Error.prepareStackTrace = function (err, stack) {
    return stack;
  };
  Error.captureStackTrace(this, arguments.callee);
  this.message = msg;
  this.name = 'CustomError';
};
CustomError.prototype.__proto__ = Error.prototype;

步骤2:使用Domain捕获未捕获的错误

function foo() {
  throw new CustomError('`foo` has been removed in favorof `bar`');
};
var d = require('domain').create();
d.on('error', function(err) {
    /*
     * customize the output here.
     */
});
d.run(function() {
  foo();
});

步骤3:自定义输出。结构化堆栈跟踪是一个由CallSite对象组成的数组,每个对象代表一个堆栈帧。CallSite对象定义了这些方法。

  for(var index=0; index<err.stack.length; index++){
    var frame = err.stack[index];
    var unit = frame.getFunctionName() || frame.getMethodName();
    if (unit === null) {
      unit = 'function()';
    } else {
      unit += '()'
    }
    if (index === 0) {
      console.error('%s:%d:%d'n  %s'n  ^',
        frame.getFileName(),
        frame.getLineNumber(),
        frame.getColumnNumber(),
        unit);
      console.error('Error: ' + err.message);
    } else {
      console.error('    at %s (%s:%d:%d)',
        unit,
        frame.getFileName(),
        frame.getLineNumber(),
        frame.getColumnNumber());
    };
  }; // END. stack trace

运行这个程序,我们得到以下输出:

/home/ray/dev/test/error.js:57:9
  foo()
  ^
Error: `foo` has been removed in favorof `bar`
    at function() (/home/ray/dev/test/error.js:53:3)
    at b() (domain.js:183:18)
    at Domain.run() (domain.js:123:23)
    at function() (/home/ray/dev/test/error.js:52:3)
    at Module._compile() (module.js:456:26)
    at Module._extensions..js() (module.js:474:10)
    at Module.load() (module.js:356:32)
    at Module._load() (module.js:312:12)
    at Module.runMain() (module.js:497:10)