Sentry-javascript: 使用键捕获的非错误异常:错误、标题、消息、名称、确定

创建于 2019-10-28  ·  48评论  ·  资料来源: getsentry/sentry-javascript

  • [x] 查看文档: https :
  • [x] 搜索现有问题: https :
  • [x] 使用最新版本: https :
  • [x] 从您的 Sentry 帐户提供受影响事件的链接 (https://sentry.io/share/issue/0f0aeecaa08746389b64945abd4544fd/)

套餐+版本

  • [x] @sentry/browser
  • [ ] @sentry/node
  • [ ] raven-js
  • [ ] raven-node _(节点的乌鸦)_
  • [ ] 其他:
  • [x] @angular/core

版本:

5.7.1 (@sentry/browser)
8.2.11 (@angular/core)

描述

我对带有全局 ErrorInterceptor 的 Angular 应用程序进行了初始设置
在这里我如何发送它

    const eventId = Sentry.captureException(error.originalError || error);
    Sentry.showReportDialog({ eventId });

我一次又一次地得到这个(用键捕获的非错误异常:错误、标题、消息、名称、确定)错误,并且无法理解描述中的错误以及如何重现它。

Needs Reproduction

最有用的评论

我们目前正在使用以下内容来忽略它。

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

所有48条评论

这意味着您提供的对象不是Error的实例,它保存了 Angular 应用程序中的堆栈跟踪。

您应该(如消息所指)根据您的需要使用Sentry.captureException(error.error)Sentry.captureException(error.message)

@kamilogorek哦好的)tnx

@kamilogorek仍然收到这个错误,即使有这个

    const exception = error.error || error.message || error.originalError || error;
    const eventId = Sentry.captureException(exception);

+1,无论我怎么说,仍然会收到此错误

sentry.error-handler.ts

export class SentryErrorHandler extends GeneralErrorHandler {
  ...
  handleError(error) {
    ...
    const exception = error.originalError || error.error || error
    Sentry.captureException(exception)
  }
}

包.json

{
  ...
  "@angular/core": "^8.2.11",
  "@sentry/browser": "^5.7.1",
  ...
}

我决定这样做

Sentry.init({
            dsn: environment.sentryUrl,
            beforeSend(event, hint) {
                /* tslint:disable:no-string-literal only-arrow-functions */
                const isNonErrorException =
                    event.exception.values[0].value.startsWith('Non-Error exception captured') ||
                    hint.originalException['message'].startsWith('Non-Error exception captured');
                /* tslint:enable:no-string-literal only-arrow-functions */

                if (isNonErrorException) {
                    // We want to ignore those kind of errors
                    return null;
                }
                return event;
            }
        });

感谢您的解决方法@gchronos! 我希望很快就会有一个潜在的修复。

只是插嘴说我也遇到了这些错误。 我正在使用 Angular 8,在阅读了很多关于此的问题后,我意识到这可能是我没有在错误处理组件中正确处理错误的情况。 我已经尝试了其他人建议的解决方法,在传递给 captureException 之前定义异常,但这并没有减少错误。 如果有人可以对此提供进一步的意见,那就太好了,否则我只能使用 GChronos 的(谢谢!)解决方案。

+1

+1

有人可以提供我可以用来调试的重现吗? 我尝试使用基本 angular-cli 应用程序,但无法重现此行为。 谢谢!

@kamilogorek我相信您可以初始化一个新的 Angular 8 项目,并向返回 500 的端点发出 http 请求,而不是在 http 服务中捕获错误,因此它会传播到 Sentry。

我可以提供更多信息,这是我们的 ErrorHandler:

@Injectable()
export class SentryErrorHandler implements ErrorHandler {
  constructor() { }
  handleError(error) {
    Sentry.captureException(error.originalError || error.error || error);
  }
}

在我们的 Sentry 跟踪中,我们总是会得到这些事件的重复事件:

  • Object.a使用键捕获的非错误异常:...
  • captureException使用键捕获的非错误异常:...

(其他事件正常报告为列表中的一项)

我们收集了数百个这样的“非错误”事件,有趣的是,它们都有以下共同点:

  • 浏览器名称:三星互联网 100%
  • 浏览器:三星互联网 9.4 100%

错误主要如下:

{
  error: [Object], 
  headers: [Object], 
  message: Http failure during parsing for https://foo.bar/baz, 
  name: HttpErrorResponse, 
  ok: False, 
  status: 200, 
  statusText: OK, 
  url: https://foo.bar/baz
}

好的,我呈现了 SentryErrorHandler 可注入并实现了 ErrorHandler 而不是扩展,对我来说不再有类似的问题。
所以我从

export class SentryErrorHandler extends ErrorHandler {

 constructor() {
     super();
 }

 handleError(err: any): void {
     if (environment.production === true || environment.preprod === true) {
         Sentry.captureMessage(err.originalError || err);
     }
     throw err;
 }
}

@Injectable()
export class SentryErrorHandler implements ErrorHandler {

 constructor() { }

 handleError(err: any): void {
     if (environment.production === true || environment.preprod === true) {
         Sentry.captureException(err.originalError || err);
     }
     throw err;
 }
}

我的第一个配置使用了 2 年没有问题,但自从升级到 Angular 8 以来,我有几个哨兵异常。

@jonathan-payiq 你能找出导致这种情况的原因吗? 或者你现在只是忽略所有这些非错误异常?

我们目前正在忽略它们。
我们从面包屑中发现当 web 视图/浏览器在后台(不可见)时会发生这些,因此我们的解决方法是防止在页面不可见时发生获取。 显然,三星浏览器在后台处理网络刷新很糟糕。

@jonathan-payiq 你到底是怎么忽略他们的? 提前致谢。

我们目前正在使用以下内容来忽略它。

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

@kamilogorek你能重现这个问题吗?

关闭问题,因为原始问题似乎已部分解决或有一个有效的解决方案。 如果它仍然是一个问题,我希望有人用新的描述创建一个新问题。
如果它仍然相关,请不要犹豫,ping 我,我会很乐意重新打开并处理它。
干杯!

它没有得到解决。 我只是尝试将 Sentry 与 Angular 8 集成并发现了这个问题。

我不明白 Sentry 怎么能声称开箱即用的设置,这是完全错误的。

我不明白 Sentry 怎么能声称开箱即用的设置,这是完全错误的。

@Rush提供了一个可重现的案例,您可以在其中解释并展示问题所在,然后我们可以验证您的声明。

@kamilogorek 实话实说,自从 6 个月以来一直没有与 Angular 合作,这里有足够的报告来证实这一点,因此 IMO 不需要进一步的重现案例,你可以很容易地自己找到它。 我知道我自己没有,因为我们在使用 Angular v8 和现在使用 v9(没有源映射)的项目中遇到了同样的问题。

没错,而且我付钱请 Sentry 为我做这项工作。 这不是一个开源项目,我确实希望自己动手。

我喜欢哨兵,但我可以寻找替代品......

我使用了一个https://github.com/gothinkster/angular-realworld-example-app应用程序作为例子,只是为了每个人也可以做同样的复制。

Barebone 克隆了应用程序,遵循 Sentry 的 Angular 文档并上传了源地图。 这是结果。


示例 1:破坏的逻辑

Angular 在错误处理程序中为您提供了什么 + 我们捕获了什么事件:

Screenshot 2020-04-16 at 12 01 13

它在 UI 中的外观:

Screenshot 2020-04-16 at 12 07 02

注意:一切都已就绪,您可以轻松地指出被破坏的正确代码行、错误消息和错误类型是正确的,因为 Angular 为您提供了一个完整的Error对象。


示例 2:中断的服务调用

Angular 在错误处理程序中为您提供了什么 + 我们捕获了什么事件:

Screenshot 2020-04-16 at 12 00 49

它在 UI 中的外观:

Screenshot 2020-04-16 at 12 07 12
Screenshot 2020-04-16 at 12 08 03

注意:没有办法知道抛出了什么类型的错误,因为 Angular 没有给你这些信息。 但是,您可以查看序列化数据以判断存在“404 Not Found”错误,这_最有可能_来自无效的 XHR 调用。 然后,您可以调查面包屑流,以查看_实际上_对给定 url(在本例中包含错字)的 XHR 调用,然后单击触发它的确切 DOM 元素。 有了这些信息,在 99% 的情况下应该足以解决问题。


我们只能使用框架给我们的东西。 否则,我们将不得不对框架本身进行猴子修补。

我们只能使用框架给我们的东西。 否则,我们将不得不对框架本身进行猴子修补。

这是您说“不是我们的问题”的方式吗? 在切换到哨兵(来自一些竞争对手)之前,这些 XHR 错误被捕获得很好,他们使用了相同的安装方法和角度错误处理程序。

@kamilogorek作为供应商,您还可以使用该框架开票。 我相信它会引起一些注意。

在切换到哨兵(来自一些竞争对手)之前,这些 XHR 错误被捕获得很好,他们使用了相同的安装方法和角度错误处理程序。

@szechyjs那么如果您可以共享解决方案

...您也可以使用该框架打开一张票。 我相信它会引起一些注意。

我刚刚在哨兵支持下打开了一张票并引用了这个问题。

这里的路人。 就我而言,我想在 react native 中报告已处理的拒绝,但我最终看到了与 OP 相同的错误。 由于the object you provide is not an instance of Error ,我开始使用下面的。

export interface IError extends Error {
  code?: ErrorCode
  msg?: string
}

export const appError = (code: ErrorCode, msg: string = ''): IError => {
  const errmsg = `code: ${code}, msg: ${msg}`
  const err: IError = new Error(errmsg)
  err.code = code
  err.msg = msg
  err.name = 'appError'
  return err
}

然后我打电话

export const logError = (err: Error) => {
  sentry.captureException(err)
}

我看到

スクリーンショット 0032-05-24 1 58 38

希望这可以帮助!

就我而言,Sentry 的 Breadcrumbs 部分对我查明原因有很大帮助。 它主要发生在某些外部 API 上有一些 404 时。

文档更新和必要的 JS SDK 更改即将到来:

https://github.com/getsentry/sentry-docs/pull/1695/
https://github.com/getsentry/sentry-javascript/pull/2601

应该在本周发布! :)

很容易解决这个问题(因为这只会发生在 HTTP 拦截错误中):

handleError(error: Error | HttpErrorResponse | any) {
      // ... 
      if (error.constructor.name === "HttpErrorResponse") {
                error.error.Message + " (" + error.message + ")";
                error = error.error;
      }
      // ...
      Sentry.captureMessage(err.originalError || err.error || error);

     throw err;
 }

新文档和5.16.0刚刚发布 - https://docs.sentry.io/platforms/javascript/angular/
我试图使其尽可能明确和详细,这就是为什么它“可能看起来”像很多代码。

@kamilogorek我在 Vue 应用程序上也遇到了这个问题。 那边有修吗?

同样在这里。 异常在 vuejs sentry 集成错误处理程序中抛出。
https://sentry.io/share/issue/eaf13a2455e04150aaaab595d0d7bafe/

@sblawrie你到底有什么问题? 请提供更多详细信息。
@cincauhangus它看起来像在您的代码中的某个地方,您正在使用abort, always, catch, done键)。

就像是:

const promise = new Promise((resolve, reject) => (...));
// somehow somewhere in the code
function foo () {
  // ...
  throw promise
}

所以 Vue 的errorHandler得到了一个完整的 promise 对象,它期望是一个Error实例。

@kamilogorek感谢您的澄清。 我已经进行了一些更改,并将监控它是否仍然存在问题。

使用 Angular 8 并且有同样的问题 Non-Error 异常。 修改示例 'extractError' 代码如下:

private static extractError(error: any) {
    // Try to unwrap zone.js error.
    // https://github.com/angular/angular/blob/master/packages/core/src/util/errors.ts
    if (error && error.ngOriginalError) {
      error = error.ngOriginalError;
    }
    // We can handle messages and Error objects directly.
    if (typeof error === 'string' || error instanceof Error) {
      return error;
    }
    // If it's http module error, extract as much information from it as we can.
    if (error instanceof HttpErrorResponse) {
      // The `error` property of http exception can be either an `Error` object, which we can use directly...
      if (error.error instanceof Error) {
        return error.error;
      }
      // ... or an`ErrorEvent`, which can provide us with the message but no stack...
      if (error.error instanceof ErrorEvent) {
        return error.error.message;
      }
      // ...or the request body itself, which we can use as a message instead.
      if (typeof error.error === 'string') {
        return `Server returned code ${error.status} with body "${error.error}"`;
      }
      // If we don't have any detailed information, fallback to the request message itself.
      return error.message;
    }

    // ***** CUSTOM *****
    // The above code doesn't always work since 'instanceof' relies on the object being created with the 'new' keyword
    if (error.error && error.error.message) {
      return error.error.message;
    }
    if (error.message) {
      return error.message;
    }
    // ***** END CUSTOM *****

    // Skip if there's no error, and let user decide what to do with it.
    return null;
  }

根据上面@untilinvite 的 beforeSend示例修改了我的 Sentry.init https://github.com/getsentry/sentry-javascript/issues/2169的第二条日志消息,也将其解析为非错误。

 Sentry.init({
        dsn: AppConfig.envSettings.sentryDSN,
        maxBreadcrumbs: 50,
        environment: this.getEnvName(),
        integrations: [new Sentry.Integrations.Breadcrumbs({ console: false })],
        beforeSend(event, hint) {
          // Note: issue with double entries during http exceptions: https://github.com/getsentry/sentry-javascript/issues/2169
          // Note: issue with a second entry not being set correctly (as a non-error): https://github.com/getsentry/sentry-javascript/issues/2292#issuecomment-554932519
          const isNonErrorException = event.exception.values[0].value.startsWith('Non-Error exception captured');
          if (isNonErrorException) {
            if (!event.extra.__serialized__) {
              return null;
            }
            let realErrMsg = event.extra.__serialized__.error ? event.extra.__serialized__.error.message : null;
            realErrMsg = realErrMsg || event.extra.__serialized__.message;
            // this is a useless error message that masks the actual error.  Lets try to set it properly
            event.exception.values[0].value = realErrMsg;
            event.message = realErrMsg;
          }
          return event;
        }
      });

我们已经在5.16.0版本中添加到文档中进行了更改,但我们仍然收到Non-Error exception captured with keys: error, headers, message, name, ok错误。 我希望@sentry/angular包能解决这些问题吗?

角度:v9.1
哨兵:v5.20

@szechyjs您是否还阅读了有关 http 拦截器的第二部分? 这通常是无法正确检测到错误的主要问题 - https://docs.sentry.io/platforms/javascript/angular/

@szechyjs您是否还阅读了有关 http 拦截器的第二部分? 这通常是无法正确检测到错误的主要问题 - https://docs.sentry.io/platforms/javascript/angular/

我们没有使用拦截器。

您好,我在这个问题上花了一些时间,发现HttpErrorResponse类型的错误中的error.error.message不一定包含任何信息。 如果我们查看构造函数,我们会看到 Angular 在根对象上而不是在ErrorEvent上设置 message 属性。

https://github.com/angular/angular/blob/cb3db0d31b91bea14c7f567fe7e7220b9592c11b/packages/common/http/src/response.ts#L345

通过更改这一行https://github.com/getsentry/sentry-javascript/blob/8eb72865dcd62ff719441105c7eda28007a07e9d/packages/angular/src/errorhandler.ts#L112

if (error.error instanceof ErrorEvent && error.error.message)

错误处理程序继续执行return error.message;并抛出预期的错误。

很棒的收获@jakkn ,谢谢! 更新了 PR https://github.com/getsentry/sentry-javascript/pull/2903 中的处理程序

我在刚刚继承的 Express 应用上遇到了这个问题。 不知道这是如何发生的,但对于应用程序抛出的大多数错误似乎都会发生这种情况,我正在使用文档中的标准 Express 设置。

例如https://sentry.io/share/issue/bfd4f674c10b4b4a8b6a291dde8e2a66/

我遇到了同样的错误,尽管它是针对快速请求处理程序而不是角度的。 基本上我是用 pojo 而不是 Error 对象调用next 。 我在自己的 express 错误处理程序中做了一些有趣的事情来将它变成有趣的东西,但是因为 sentryio 请求中间件先行,所以它没有得到这个编组错误。

最后,创建了一个效用函数,将提供的任何东西都变成更合理的东西:

export const handleMaybeError = err => {
  if (err instanceof Error) return err
  const newErr = new Error(err.message || 'unexpected')
  for (const [key, value] of Object.entries(err)) {
    newErr[key] = value
  }
  return newErr
}

export const someController = (req, res, next) => {
  try {
    await handleResponse(req, res)
  } catch (err) {
    next(handleMaybeError(err))
  }
}

我认为这会混合堆栈跟踪,但实际上如果它是一个 pojo 传递到这里,无论如何都没有堆栈跟踪。

在我们的实例中,在修复此问题之前,报告的绝大多数事件都是针对此特定问题的,并且由于它是一个长时间运行的节点 Web 服务器,因此面包屑几乎无用——并且所有错误都集中在这一事件类型中。

const 异常 = error.error || 错误信息 || error.originalError || 错误;

这将评估为真/假

const 异常 = error.error || 错误信息 || error.originalError || 错误;

这将评估为真/假

不太可能,虽然可能。 这一切都归结为您在流中发送的“错误”。 但毕竟,这应该包括某种有用的信息。

此页面是否有帮助?
0 / 5 - 0 等级