Sentry-javascript: Allow passing an object to `scope.setExtra` (et al) ?

Created on 25 Oct 2018  路  10Comments  路  Source: getsentry/sentry-javascript

I'm creating an ErrorBoundary react component, and instead of doing this:

  componentDidCatch (error, errorInfo) {
    this.setState({ error, errorInfo })
    Sentry.configureScope(scope => {
      Object.keys(errorInfo).forEach(key => {
        scope.setExtra(key, errorInfo[key])
      })
    })
    Sentry.captureException(error)
  }

It would be nice if scope.setExtra supported receiving an object (containing multiple "extra" key-extra pairs) so we could do something like this (scope.setExtra would do the Object.keys loop internally):

  componentDidCatch (error, errorInfo) {
    this.setState({ error, errorInfo })
    Sentry.configureScope(scope => { scope.setExtra(errorInfo) })
    Sentry.captureException(error)
  }

Any thoughts around implementing this? Thanks!

Discussion Improvement

Most helpful comment

Just a quick update on the initial topic:

We decided to add additional functions on the scope

setTags, setExtras & clearBreadcrumbs

Version 5.0.0 will include those and therefore make the boilerplate code obsolete.

I am closing this issue, PR can be tracked here:
https://github.com/getsentry/sentry-javascript/pull/1919

All 10 comments

Hey @benalman-toast! Unfortunately, we have a commonly agreed upon API, for all our supported languages. This change would require an update to Rust, C, Pyhon, .Net, PHP and all our other SDKs and documentation.

Sounds like a useful update, then! ;)

(whoops.)

It's fine in JS or Python, but overloading in Rust is not that nice though. We are trying to be as simplistic as possible, with giving the end user tools to create their own utilities if necessary.
We will still probably need to shave down some APIs, as bundle size is crucial nowadays, but we are already not shining in this part 馃槄

Don't want to sound too picky, but it can already be written as a one-liner with for (const key in errorInfo) scope.setExtra(key, errorInfo[key]); (I know it doesn't check for hasOwnProperty but in most cases, it's data you have control over anyway.

Also, in your case, you probably want to limit the additional data to only current scope, so it'd be:

componentDidCatch (error, errorInfo) {
  this.setState({ error, errorInfo })
  Sentry.withScope(scope => {
    for (const key in errorInfo) scope.setExtra(key, errorInfo[key]);
    Sentry.captureException(error);
  });
}

I'm trying to add that stack as an extra, but it gets filtered out:

capture d ecran 2018-11-23 15 56 56

Here is my code:

  componentDidCatch(error, info) {
    console.log('componentDidCatch', info.componentStack)
    Sentry.withScope((scope) => {
      scope.setExtra('extraTest1', 'ok')
      scope.setExtra('extraTest2', true)
      scope.setExtra('extraTest3', 1337)
      scope.setExtra('componentStack', info.componentStack)
      scope.setExtra('extraTest4', {ok: true})
      scope.setExtra('extraTest5', {ok: {ok: 'ok'}})
      Sentry.captureException(error)
    })

And here is the componentStack value (as you can see it's not that long):

    in Calendar (created by Uncontrolled(Calendar))
    in Uncontrolled(Calendar) (at src/index.js:127)
    in div (at Events.js:145)
    in Events (created by Connect(Events))
    in Connect(Events) (created by Route)
    in Route (at Authenticated.js:169)
    in Switch (at Authenticated.js:143)
    in div (at Authenticated.js:142)
    in div (at Authenticated.js:123)
    in Authenticated (created by Connect(Authenticated))
    in Connect(Authenticated) (created by Route)
    in Route (at App.js:134)
    in Suspense (at App.js:133)
    in IntlProvider (at App.js:130)
    in App (created by Connect(App))
    in Connect(App) (created by Route)
    in Route (at web/index.js:52)
    in Router (at web/index.js:51)
    in Provider (at web/index.js:50)

Why does it get filtered out? Newlines? Size? I'd like to include it in my report anyway :/

Also, when I only set my componentStack extra, I get this:

capture d ecran 2018-11-23 16 09 45

I was about to rise the "what about the scope listeners" argument but I found out it's invalid.

I'll leave it here for the sake of anyone looking for the answer in the future:

Yes, it's true Scope#set* does Scope#notifyScopeListeners

eg.

https://github.com/getsentry/sentry-javascript/blob/28b8164877cf151bba42374d90309441f5d7bb7d/packages/hub/src/scope.ts#L106-L114

so that one will be called many times in case setter is called in a loop.
But Scope#notifyScopeListeners has a mechanism built-in to discard consecutive calls:

https://github.com/getsentry/sentry-javascript/blob/28b8164877cf151bba42374d90309441f5d7bb7d/packages/hub/src/scope.ts#L53-L66

So the only downside is syntax regardless of how heavy scope listeners would be.

@kamilogorek any clue about this?

@antoinerousseau sorry for taking that long. It's because your componentStack matches our default data sanitizers 馃槄

https://github.com/getsentry/sentry/blob/0f600d86646a4d6a51390634121d4004e01f41c3/src/sentry/constants.py#L168-L171

Authenticated string matches auth substring.

Go to your project's privacy settings in Sentry and turn off default scrubbers.

image

@kamilogorek oh ok, thank you very much!

Just a quick update on the initial topic:

We decided to add additional functions on the scope

setTags, setExtras & clearBreadcrumbs

Version 5.0.0 will include those and therefore make the boilerplate code obsolete.

I am closing this issue, PR can be tracked here:
https://github.com/getsentry/sentry-javascript/pull/1919

Was this page helpful?
0 / 5 - 0 ratings