Sentry-javascript: Error not shown in console and Out of memory error when trying to print it using console.error

Created on 20 Nov 2018  路  9Comments  路  Source: getsentry/sentry-javascript

Package + Version

  • [ X] @sentry/browser
  • [ ] @sentry/node
  • [ ] raven-js
  • [ ] raven-node _(raven for node)_
  • [ ] other:

Version:

4.3.2

Description

Integrating the sentry browser client with Angular using an Angular Error Handler, however I can not see the errors in console anymore. If I call super.handleError() to use the parent class to log the error in the console, the browser freezes with Out of memory error.

Here is the code for errorhandler

@Injectable()
export class SentryErrorHandler extends ErrorHandler {
    constructor(private injector: Injector, private appConfig: AppConfig) {
        super();
        Sentry.init({
            dsn: this.injector.get(SENTRY_DSN)
        });
    }


    handleError(error) {
        Sentry.captureException(error.originalError || error);
        throw error;
    }
}

And the implementation where it freezes

@Injectable()
export class SentryErrorHandler extends ErrorHandler {
    constructor(private injector: Injector, private appConfig: AppConfig) {
        super();
        Sentry.init({
            dsn: this.injector.get(SENTRY_DSN)
        });
    }


    handleError(error) {
        Sentry.captureException(error.originalError || error);
        super.handleError(error);
        throw error;
    }
}

Question

Most helpful comment

@mlakhara @Oikio so the issue is that Angular attaches A LOT of additional data to it's error object (over 2 millions characters when stringified - yup, 2 millions).

The way around it now, is to remove it from the breadcrumbs, so we will remove it, but still have an error in the crumb. This way we won't have to serialize it.

Sentry.init({
  beforeBreadcrumb(crumb) {
    if (crumb.category === "console") {
      for (const arg of crumb.data.extra.arguments) {
        delete arg.ngDebugContext;
        delete arg.ngErrorLogger;
      }
    }
    return crumb;
  }
});

All 9 comments

Use console.error directly instead. Your config will create infinite loop here. Also take Sentry.init outside of constructor if possible.

@Injectable()
export class SentryErrorHandler extends ErrorHandler {
    handleError(error) {
        const err = error.originalError || error;
        if (SOME_DEV_MODE) console.error(err);
        Sentry.captureException(err);
        throw error;
    }
}

I was just going to open same issue. I have initialization outside of injectable class. I have also tried to run captureException outside of ngZone - didn't help.
So as in case above code ends up in endless cycle.
Here are screenshots, hope it might help, I'm still stuck on this one.
screen shot 2018-11-22 at 11 09 08
screen shot 2018-11-22 at 11 09 36

At first, I tried calling console.error directly but it was not working hence tried super.handleError as done in raven-js documentation (which is deprecated, I know, but I hoped it would work).
In short using console.error or super.handleError, both are behaving the same way.

@Oikio Yes, it dies on the same line trying to serialize the circular object.

@Oikio @mlakhara would it be possible to provide a repro-case by one of you? I'm not working with Angular on daily basis and it'd take me quite a long time to even reproduce this.
Thanks!

Cool, I am on it.

This is the github repo

https://github.com/mlakhara/sentry-test

Although the code does not break but the browser freezes for 5 seconds, so I guess it depends on the size of exception stracktrace.

click-handler

@mlakhara @Oikio so the issue is that Angular attaches A LOT of additional data to it's error object (over 2 millions characters when stringified - yup, 2 millions).

The way around it now, is to remove it from the breadcrumbs, so we will remove it, but still have an error in the crumb. This way we won't have to serialize it.

Sentry.init({
  beforeBreadcrumb(crumb) {
    if (crumb.category === "console") {
      for (const arg of crumb.data.extra.arguments) {
        delete arg.ngDebugContext;
        delete arg.ngErrorLogger;
      }
    }
    return crumb;
  }
});

Looks like it's the issue (Angular puts a lot of information there, at least in dev mode), solution helped partially, I couldn't see logs in console with code snippet from @kamilogorek. Also deleting ng props from original object is not a good idea. I ended up with this code, worked for me.

  beforeBreadcrumb: crumb => {
    const shrinkedCrumb = { ...crumb };
    if (crumb.data && crumb.data.extra && crumb.data.extra.arguments) {
      shrinkedCrumb.data.extra = {
        ...crumb.data.extra,
        arguments: crumb.data.extra.arguments.map((arg: any) => {
          const shrinkedArg = { ...arg };
          delete shrinkedArg.ngDebugContext;
          delete shrinkedArg.ngErrorLogger;
          return shrinkedArg;
        })
      };
    }
    return shrinkedCrumb;
  }

But don't rethrow error in your ErrorHandler#handleError, just log. I have this behavior (needs more investigation): rethrow doesn't log exception to console, console.error with rethrow logs twice the first time.

Thanks @kamilogorek and @Oikio, your snippets worked perfectly.

@Oikio I added a custom property to the error object in my error handler and called console.error only when the property was not available, to tackle the error being logged twice.


    handleError(error) {
        Sentry.captureException(error.originalError || error);

        if (!error.__logged) {
            console.error(error);
            error.__logged = true;
        }


        throw error;
    }


Was this page helpful?
0 / 5 - 0 ratings