猿问

Sentry.io 在异步 Node.js 服务器上管理错误范围/上下文

基本上你在 Node.js 中有并发请求。并且您可能希望使用特定于每个请求的数据来丰富可能的错误。可以通过以下方式在应用程序的不同部分收集此特定于请求的数据


Sentry.configureScope(scope => scope.setSomeUsefulData(...))

Sentry.addBreadcrumb({ ... })

稍后在深度嵌套的异步函数调用中的某个地方抛出错误。Sentry 如何知道先前收集的哪些数据实际上与此特定错误相关,考虑到请求是同时处理的,并且在发生错误时无法访问某个哨兵“范围”来获取与此特定请求相关的数据,从而导致在错误中。


还是我必须通过所有函数调用传递哨兵作用域?喜欢


server.on('request', (requestContext) => {

  // Create new Sentry scope

  Sentry.configureScope(sentryScope => {

    Products.getProductById(id, sentryScope); // And pass it on

  });

});


// all the way down until...


function parseNumber(input, sentryScope) {

  // ...

}

或者哨兵是否使用某种魔法将特定数据映射到相关事件?或者我错过了什么?


慕婉清6462132
浏览 208回答 1
1回答

30秒到达战场

看起来他们使用 Node.js 域(https://nodejs.org/api/domain.html)为每个请求创建一个单独的“上下文”。从 Sentry 文档中,您需要使用 requestHandler 才能正常工作。例如对于快递(https://docs.sentry.io/platforms/node/express/):const express = require('express');const app = express();const Sentry = require('@sentry/node');Sentry.init({ dsn: 'https://963bad1904fe48b18c1866f10e69eff8@sentry.io/1240240' });// The request handler must be the first middleware on the appapp.use(Sentry.Handlers.requestHandler());// All controllers should live hereapp.get('/', function rootHandler(req, res) {  res.end('Hello world!');});处理程序看起来像这样:(来自:@sentry/node/dist/handlers.js)function requestHandler(options) {    return function sentryRequestMiddleware(req, res, next) {        if (options && options.flushTimeout && options.flushTimeout > 0) {            // tslint:disable-next-line: no-unbound-method            var _end_1 = res.end;            res.end = function (chunk, encoding, cb) {                var _this = this;                sdk_1.flush(options.flushTimeout)                    .then(function () {                    _end_1.call(_this, chunk, encoding, cb);                })                    .then(null, function (e) {                    utils_1.logger.error(e);                });            };        }        var local = domain.create();        local.add(req);        local.add(res);        local.on('error', next);        local.run(function () {            core_1.getCurrentHub().configureScope(function (scope) {                return scope.addEventProcessor(function (event) { return parseRequest(event, req, options); });            });            next();        });    };}exports.requestHandler = requestHandler;因此,您可以看到根据新请求创建的新域。我主要是通过发现这个问题来找到这个信息的:https : //github.com/getsentry/sentry-javascript/issues/1939如果您想将“上下文”添加到 Node 后端的其他异步部分(例如,如果您有工作人员/线程/某些工作不是从 HTTP 请求启动的……),上面的问题中有一些示例说明了如何实现完成(通过手动创建集线器/域..)。如果您有兴趣,现在也可以使用 async_hooks 来保持 Node.js 中具有各种异步函数/回调/setTimeouts 的上下文的某种意义:https ://nodejs.org/api/async_hooks.html这是一个很好的介绍:https://itnext.io/request-id-tracing-in-node-js-applications-c517c7dab62d?以及一些实现此功能的库:https://github.com/Jeff-Lewis/cls-hookedhttps://github.com/vicanso/async-local-storage例如,这样的事情应该工作:const ALS = require("async-local-storage");function withScope(fn, requestId) {  ALS.scope();  ALS.set("requestId", requestId, false);  return await fn();}async function work() {  try {    await part1();    await part2();  } catch(e) {     Sentry.withScope((scope) => {       scope.setTag("requestId", ALS.get("requestId"));       Sentry.captureException(new Error("..."))     })   }}withScope(work, "1234-5678");不过,您必须自己跟踪面包屑,例如添加面包屑:ALS.set("breadcrumbs", [...ALS.get("breadcrumbs"), new_breadcrumb]);您需要在 Sentry 的 beforeSend() 回调中手动设置这些:beforeSend: function(data) {  data.breadcrumbs = ALS.get("breadcrumbs");  return data;}
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答