At the moment I'm trying to integrate raven-js into our webapp, but I have hit a roadblock. The application is mostly single page, but at some points it navigates to other sites, especially in some error cases. So what I end up with is code similar to this:
try {
doSomeCrazyThingThatMightFail()
}聽catch (err) {
Raven.captureException(e)
window.location.url = 'my.error.page.com'
}
The issue here is that this fails to report the error, as the sending of the report happens asynchronously.
What I'm looking for is something like this:
Raven.captureException(e, function () {
// We are save the exception was sent over the network
window.location.url = 'my.error.page.com'
})
Looking at the code/docs I could not find the ability to do this, but maybe I missed something.
Hmm, it might be possible that we can add this.
At the moment, I'd guess the best way is with the events that are dispatched. We dispatch an event for ravenSuccess
and ravenFailure
. Does that help?
I agree we can likely do something better here though, I just don't think this case has come up before.
https://github.com/getsentry/raven-js/issues/293 might not be a terrible option here either since iirc sendBeacon()
will send in the browser async even when navigating away from the page.
In theory sendBeacon
could help but as the browser support for that does not seem to be very complete I don't think that will help us.
I could hack something together on top of the events for success and failure but the issue is still that I need to map those then onto the corresponding captureException
call.
@Dignifiedquire This isn't really a solution, but you could map them together based on event ids.
So the event sends along the entire data blob. https://github.com/getsentry/raven-js/blob/master/src/raven.js#L815 which has data.event_id
.
And you can do Raven.lastEventId()
I've never tried to do this, but I think all the primitives are there.
With that said, I don't think it's unreasonable for us to provide a callback for this. We just don't at the moment. :)
This would be very simple to do, already the codebase has:
// other functions
_send: function(data) {
// do lots of stuff
this._sendProcessedPayload(data);
},
// other functions
_sendProcessedPayload: function(data, callback) {
// do lots of stuff
(globalOptions.transport || this._makeRequest).call(this, {
url: url,
auth: auth,
data: data,
options: globalOptions,
onSuccess: function success() {
self._triggerEvent('success', {
data: data,
src: url
});
callback && callback();
},
onError: function failure(error) {
self._triggerEvent('failure', {
data: data,
src: url
});
error = error || new Error('Raven send failed (no additional details provided)');
callback && callback(error);
}
});
}
// other functions
But we are never actually passing the callback through.
And I have a similar scenario when I need to navigate away once some actions are taken by the user, any of which could cause an exception. Ideally Raven.captureException/captureMessage would return a promise but in the meantime accepting a callback in the options is fine.
In the meantime for anyone else interested this works, although I can't say it's super fantastic:
let capture = (e) => {
return new Promise((resolve, reject) => {
Raven.captureException(e);
let requestEventId = Raven.lastEventId();
let successFunc = (e) => {
let responseEventId = e.data.event_id;
if (requestEventId === responseEventId) {
window.removeEventListener("ravenSuccess", successFunc);
resolve();
};
};
let failureFunc = (e) => {
let responseEventId = e.data.event_id;
if (requestEventId === responseEventId) {
window.removeEventListener("ravenFailure", failureFunc);
reject();
};
};
window.addEventListener("ravenSuccess", successFunc);
window.addEventListener("ravenFailure", failureFunc);
});
};
We'll be reworking this part in the next major version and are aware of the culprits. Closing it for now.
Is this functionality released yet?
@jmahony not yet, we'll announce the release somewhere at the end of Q3
Most helpful comment
@jmahony not yet, we'll announce the release somewhere at the end of Q3