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
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)
Not sure if related but isn't extra
suppose to be an object?
I just tested it using your code sample, without any modificaitons, and it's all where it should be :)
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?
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:
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"
}
@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
Hope it helps.
So if I understand it correctly, in development mode the first captureException
is ignored?
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.
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?
That's exactly what happens. See my first screenshot :)
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?
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.
If you change the order, so it's:
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.
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.
馃 Thanks for the detailed explanation!
Most helpful comment
@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.
Here are two screenshots of the output
Development
Production
Hope it helps.