Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raven.captureException() not capturing metadata #1249

Closed
wwwouter opened this issue Mar 8, 2018 · 11 comments
Closed

Raven.captureException() not capturing metadata #1249

wwwouter opened this issue Mar 8, 2018 · 11 comments

Comments

@wwwouter
Copy link

wwwouter commented Mar 8, 2018

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

With this code:

Raven.config(sentryUrl, {tags: {test0: 'test'}}).install();

  Raven.setUserContext({
           test1: 'test',
        });
        Raven.setTagsContext({ test2:'test' });
        Raven.setExtraContext({  test3:'test' });
        Raven.captureException(err.reason, { logger: 'my.module', extra: 'extra', tags: { test4:'test' } });
 Raven.captureMessage(err.reason, { level: 'warning', extra: 'extra', tags: { test5:'test' } });

A warning and an error are logged. The warning has all the specified meta data, the error only test0.

What is the expected behavior?

That captureException captures the same metadata, the same way as captureMessage.

Which versions of Raven.js, and which browser and OS are affected by this issue?
Are you using the CDN (http://ravenjs.com)?

I used both raven-js version 3.23.1 with webpack and <script src="https://cdn.ravenjs.com/3.23.1/raven.min.js" crossorigin="anonymous"></script>

Tested on Chrome Version 64.0.3282.186 on Windows 10

Did this work in previous versions of Raven.js?
Don't know, first time user.

Are you using hosted Sentry or on-premises? If on-premises, which version (e.g. 8.7.0)?
Using https://sentry.io (paid account)

@SimonSchick
Copy link
Contributor

Not sure if related but isn't extra suppose to be an object?

@kamilogorek
Copy link
Contributor

kamilogorek commented Mar 12, 2018

I just tested it using your code sample, without any modificaitons, and it's all where it should be :)

captureException

screen shot 2018-03-12 at 11 13 33
screen shot 2018-03-12 at 11 14 06
screen shot 2018-03-12 at 11 14 10

captureMessage

screen shot 2018-03-12 at 11 14 19
screen shot 2018-03-12 at 11 14 22
screen shot 2018-03-12 at 11 14 25

As @SimonSchick mentioned, extra in your captureX calls should be an object, otherwise, it's treated as an array of single character values (see screenshot).

Can you post paste link to the broken events or screenshots of them?

@wwwouter
Copy link
Author

wwwouter commented Mar 12, 2018

Hi @kamilogorek

There seems to be a problem with the type of error

I'm using react and this is my code


  public render() {
        throw new Error('test8a');
  }

public componentDidCatch(error: any, info: any) {
Raven.captureException(error, { tags: {test4: 'test' } });
Raven.captureException(new Error('test_error'), { tags: {test4: 'test' } });

this.setState({ hasError: true, sentryEventId: Raven.lastEventId() });
}

The first one ignores the tag, while the order does log it:
test_error
test8a

Looking at the POST to sentry, there seems to be a difference:

{
  "project":"xxx",
  "logger":"javascript",
  "platform":"javascript",
  "request":{
    "headers":{
      "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36",
      "Referer":"http://localhost:8080/patients"
    },
    "url":"http://localhost:8080/patients"
  },
  "exception":{
    "values":[
      {
        "type":"Error",
        "value":"test8a",
        "stacktrace":{
          "frames":[
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44494,
              "colno":37,
              "function":"response.json.then",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219058,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44471,
              "colno":9,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219061,
              "colno":16,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219028,
              "colno":29,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":144360,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81984,
              "colno":7,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81678,
              "colno":16,
              "function":"Connect.onStateChange",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":120259,
              "colno":16,
              "function":"Connect.Component.setState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":127891,
              "colno":7,
              "function":"Object.enqueueSetState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132368,
              "colno":12,
              "function":"scheduleWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132411,
              "colno":11,
              "function":"scheduleWorkImpl",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132557,
              "colno":7,
              "function":"requestWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132646,
              "colno":7,
              "function":"performWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132693,
              "colno":24,
              "function":"performWorkOnRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132045,
              "colno":7,
              "function":"renderRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122117,
              "colno":27,
              "function":"invokeGuardedCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122260,
              "colno":16,
              "function":"Object.invokeGuardedCallbackDev",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":107334,
              "colno":21,
              "function":"HTMLUnknownElement.wrapped",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122221,
              "colno":14,
              "function":"HTMLUnknownElement.callCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131967,
              "colno":26,
              "function":"workLoop",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131903,
              "colno":16,
              "function":"performUnitOfWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129904,
              "colno":16,
              "function":"beginWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129529,
              "colno":12,
              "function":"updateClassComponent",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129552,
              "colno":31,
              "function":"finishClassComponent",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":208871,
              "colno":15,
              "function":"PatientsList.render",
              "in_app":true
            }
          ]
        }
      }
    ]
  },
  "culprit":"http://localhost:8080/scripts/app.js",
  "trimHeadFrames":0,
  "extra":{
    "session:duration":572
  },
  "breadcrumbs":{
    "values":[
      {
        "timestamp":1520860418.832,
        "type":"http",
        "category":"fetch",
        "data":{
          "method":"GET",
          "url":"/api/session",
          "status_code":200
        }
      }
    ]
  },
  "event_id":"xxx"
}
{
  "project":"xxx",
  "logger":"javascript",
  "platform":"javascript",
  "request":{
    "headers":{
      "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36",
      "Referer":"http://localhost:8080/patients"
    },
    "url":"http://localhost:8080/patients"
  },
  "exception":{
    "values":[
      {
        "type":"Error",
        "value":"test_error",
        "stacktrace":{
          "frames":[
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44494,
              "colno":37,
              "function":"response.json.then",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219058,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44471,
              "colno":9,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219061,
              "colno":16,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219028,
              "colno":29,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":144360,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81984,
              "colno":7,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81678,
              "colno":16,
              "function":"Connect.onStateChange",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":120259,
              "colno":16,
              "function":"Connect.Component.setState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":127891,
              "colno":7,
              "function":"Object.enqueueSetState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132368,
              "colno":12,
              "function":"scheduleWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132411,
              "colno":11,
              "function":"scheduleWorkImpl",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132557,
              "colno":7,
              "function":"requestWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132646,
              "colno":7,
              "function":"performWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132696,
              "colno":42,
              "function":"performWorkOnRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131729,
              "colno":9,
              "function":"commitRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122117,
              "colno":27,
              "function":"invokeGuardedCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122260,
              "colno":16,
              "function":"Object.invokeGuardedCallbackDev",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":107334,
              "colno":21,
              "function":"HTMLUnknownElement.wrapped",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122221,
              "colno":14,
              "function":"HTMLUnknownElement.callCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131635,
              "colno":9,
              "function":"commitAllLifeCycles",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132289,
              "colno":18,
              "function":"commitErrorHandling",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":95172,
              "colno":32,
              "function":"UnconnectedCatchingComponent.componentDidCatch",
              "in_app":true
            }
          ]
        }
      }
    ]
  },
  "culprit":"http://localhost:8080/scripts/app.js",
  "trimHeadFrames":0,
  "tags":{
    "test4":"test"
  },
  "extra":{
    "session:duration":645
  },
  "breadcrumbs":{
    "values":[
      {
        "timestamp":1520860418.832,
        "type":"http",
        "category":"fetch",
        "data":{
          "method":"GET",
          "url":"/api/session",
          "status_code":200
        }
      },
      {
        "timestamp":1520860419.011,
        "category":"sentry",
        "message":"Error: test8a",
        "event_id":"",
        "level":"error"
      },
      {
        "timestamp":1520860419.056,
        "message":"The above error occurred in the <PatientsList> component:\n    in PatientsList (created by RouterContext)\n    in UnconnectedCatchingComponent (created by Connect(UnconnectedCatchingComponent))\n    in Connect(UnconnectedCatchingComponent) (created by AppNext)\n    in div\n    in Unknown (created by AppNext)\n    in IntlProvider (created by AppNext)\n    in AppNext (created by Connect(AppNext))\n    in Connect(AppNext) (created by AppSwitcher)\n    in AppSwitcher (created by Connect(AppSwitcher))\n    in Connect(AppSwitcher) (created by RouterContext)\n    in RouterContext (created by Router)\n    in Router\n    in Provider\n\nReact will try to recreate this component tree from scratch using the error boundary you provided, UnconnectedCatchingComponent.",
        "level":"error",
        "category":"console"
      }
    ]
  },
  "event_id":"xxx"
}

@kamilogorek
Copy link
Contributor

@wwwouter two things. Make sure that your actual ErrorBoundry is catching what it should (eg. don't trigger error from the same component that implements it - it won't work).

However, more important is that React does bubble all the errors in development mode and this is what happens in your case.

The first event, that doesn't have tags is triggered using global error handler and only second one is yours. It took me a while to debug as it's not obvious, but this is how React works. It doesn't happen in production.

const BadComponent = () => {
  throw new Error("BadComponent");
};

class ErrorBoundary extends React.Component {
  componentDidCatch(error) {
    Raven.captureException(error, {
      tags: {
        something: "awesome"
      }   
    }); 
    Raven.captureException(new Error("foo"), {
      tags: {
        something: "awesome"
      }   
    }); 
  }

  render() {
    return this.props.children;
  }
}

ReactDOM.render(
  <ErrorBoundary>
    <BadComponent />
  </ErrorBoundary>,
  document.getElementById("main")
);

Here are two screenshots of the output

Development

screen shot 2018-03-12 at 16 07 38

Production

screen shot 2018-03-12 at 16 06 59

Hope it helps.

@wwwouter
Copy link
Author

So if I understand it correctly, in development mode the first captureException is ignored?

@kamilogorek
Copy link
Contributor

Well, not really ignored. It's correctly caught by Raven, as it's a proper error. It's React that bubbles it up to the global error handler in development, where, in production, it doesn't.

@wwwouter
Copy link
Author

It is also caught in componentDidCatch, so if it's bubbled, shouldn't that result in the logging of 3 exceptions, with two that have the something:awesome tag?

@kamilogorek
Copy link
Contributor

That's exactly what happens. See my first screenshot :)

@wwwouter
Copy link
Author

Sorry if this is becoming more of on-boarding than an actual issue, but if I look at my dashboard I see only one event. Shouldn't there be two for test8a?

So if one has a tag and the other hasn't, does this result in 1 issue with 2 events? If so, should't the tag be visible? Or should there be 2 issues, with both 1 event?

@kamilogorek
Copy link
Contributor

No worries :) Ok, so there are 2 things going on.

Shouldn't there be two for test8a?

Not in this scenario:

  componentDidCatch(error) {
    Raven.captureException(error, {
      tags: {
        something: "awesome"
      }   
    }); 
    Raven.captureException(new Error("foo"), {
      tags: {
        something: "awesome"
      }   
    }); 
  }

When configured like this, notice that first captureException is exactly the same error as the one caught by the global handler. This means that they are duplicates. If you set Raven.debug = true, then you can see that it's being dropped, as we calculate duplicates based on the exception itself and a stacktrace, which in this case are the same.

screen shot 2018-03-13 at 16 10 11

If you change the order, so it's:

  • global hander for thrown error
  • your custom error, eg. new Error('foo')
  • captureException for didCatchException

Then it's not treated as a duplicate, as 2 consecutive exceptions are never the same. In this case, we send all 3 of them.

screen shot 2018-03-13 at 16 11 17

So if one has a tag and the other hasn't, does this result in 1 issue with 2 events?

That's correct. As mentioned above, events are calculated based on exception and stacktrace value, and tags are associated to the specific event.

If so, should't the tag be visible? Or should there be 2 issues, with both 1 event?

If we'd do that, it'd be very noisy. We try to group them as much as possible and assume that the same exception with the same stacktrace will always have the same tags, as it's basically thrown in the same place.

@wwwouter
Copy link
Author

🥇 Thanks for the detailed explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants