Try Atatus which provides Advanced Error Tracking and Real User Monitoring for modern web apps.
Let me explain how to get stacktraces that are reasonably complete in all browsers.
Modern Chrome and Opera fully support the HTML 5 draft spec for ErrorEvent and window.onerror
. In both of these browsers you can either use window.onerror
, or bind to the 'error' event properly:
// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
console.log(message, "from", error.stack);
// You can send data to your server
// sendError(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
console.log(e.error.message, "from", e.error.stack);
// You can send data to your server
// sendError(data);
})
Unfortunately Firefox, Safari and IE are still around and we have to support them too. As the stacktrace is not available in window.onerror
we have to do a little bit more work.
It turns out that the only thing we can do to get stacktraces from errors is to wrap all of our code in a try{ }catch(e){ }
block and then look at e.stack
. We can make the process somewhat easier with a function called wrap that takes a function and returns a new function with good error handling.
function wrap(func) {
// Ensure we only wrap the function once.
if (!func._wrapped) {
func._wrapped = function () {
try{
func.apply(this, arguments);
} catch(e) {
console.log(e.message, "from", e.stack);
// You can send data to your server
// sendError(data);
throw e;
}
}
}
return func._wrapped;
};
This works. Any function that you wrap manually will have good error handling, but it turns out that we can actually do it for you automatically in most cases.
By changing the global definition of addEventListener
so that it automatically wraps the callback we can automatically insert try{ }catch(e){ }
around most code. This lets existing code continue to work, but adds high-quality exception tracking.
var addEventListener = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
addEventListener.call(this, event, wrap(callback), bubble);
}
We also need to make sure that removeEventListener
keeps working. At the moment it won't because the argument to addEventListener
is changed. Again we only need to fix this on the prototype
object:
var removeEventListener = window.EventTarget.prototype.removeEventListener;
window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
removeEventListener.call(this, event, callback._wrapped || callback, bubble);
}
You can send error data using image tag as follows
function sendError(data) {
var img = newImage(),
src = 'http://yourserver.com/jserror&data=' + encodeURIComponent(JSON.stringify(data));
img.crossOrigin = 'anonymous';
img.onload = function success() {
console.log('success', data);
};
img.onerror = img.onabort = function failure() {
console.error('failure', data);
};
img.src = src;
}
Disclaimer: I am a web developer at https://www.atatus.com/.