是否有一种很好的方法可以跨事件发射器/事件循环边界显示生产中的错误跟踪?

时间:2019-02-27 21:27:36

标签: javascript node.js error-handling

假设我有:

const req = require('net').createConnection(80, 'localhost');

req.on('error', (error) => {
  console.error(error) // handle somehow
});

如果发生错误事件,我会得到

{ Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1117:14)
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 80 }

在终端机上。

我想查看完整的堆栈:

{ Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1117:14)
    at Object.<anonymous> (/Users/aleksey/error-handing-example.js:2:7)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 80 }

注意:我是这样人工获得完整跟踪的:

Error.captureStackTrace(this);
const req = require('net').createConnection(80, 'localhost');

req.on('error', (error) => {
  error.stack += this.stack.replace(/^.+$/, '');
  console.error(error) // handle somehow
});

我不能为所有错误执行此操作,因为这是不可持续的

有没有办法做到这一点:

  • a。以不损害生产稳定性的方式(longjohn声称它仅用于开发)?
  • b。自动吗?

1 个答案:

答案 0 :(得分:0)

这是我使用async_hooks并覆盖Error.captureStackTrace编写的骇人听闻的东西:

const ah = require('async_hooks');

const traces = new Map();

ah.createHook({
  init(id) {
    const _trace = {};
    Error.captureStackTrace(_trace);
    traces.set(id, _trace.stack.replace(/(^.+$\n){4}/m, '\n'));
  },
  destroy(id) {
    traces.delete(id);
  },
}).enable();

global.Error = class extends Error {
  constructor(message) {
    super(message);
    this.constructor.captureStackTrace(this, this.constructor);
  }

  static captureStackTrace(what, where) {
    super.captureStackTrace.call(Error, what, where);
    const trace = traces.get(ah.executionAsyncId());
    if (trace) what.stack += trace;
  }
};

要点是:

  1. 保留asyncId =>跟踪的地图
  2. 覆盖Error.captureStackTrace以在原始堆栈顶部使用来自该asyncId的跟踪

不确定其性能限制,错误和鲁棒性,但这就是我能想到的全部内容。

现在,如果我有:

const req = net.createConnection(8080);
req.once('error', err => {
  console.error(err);
});

代替

{ Error: connect ECONNREFUSED 127.0.0.1:8080
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1084:14)

我明白了

{ Error: connect ECONNREFUSED 127.0.0.1:8080
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1084:14)
    at TCPConnectWrap.emitInitNative (internal/async_hooks.js:137:43)
    at internalConnect (net.js:840:26)
    at defaultTriggerAsyncIdScope (internal/async_hooks.js:294:19)
    at GetAddrInfoReqWrap.emitLookup [as callback] (net.js:1006:9)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:62:10)
    at GetAddrInfoReqWrap.emitInitNative (internal/async_hooks.js:137:43)
    at lookup (dns.js:142:19)
    at net.js:981:5
    at defaultTriggerAsyncIdScope (internal/async_hooks.js:294:19)
    at lookupAndConnect (net.js:980:3)
    at Socket.connect (net.js:915:5)
    at Object.connect (net.js:162:17)
    at Object.<anonymous> (/Users/aleksey/epudos-lite/server/test.js:28:17)