"Theoretically, we could wrap every function call in a try/catch and we'd
have an error object in the catch block. This is bad; please don't try.
You'll have a particularly hard time with asynchronous callbacks anyways."
Couldn't disagree more with this point. Wrap the function, not the call. Something like this:
function logExceptions( fn ) {
return function() {
try {
return fn.apply( this, arguments );
} catch( e ) {
logException( e );
}
};
}
myFunction = logExceptions( function() {
// do stuff
} );
Now you just call myFunction() normally. Pretty painless.
Further, you only have to use a logger-wrapped function for your script's entry points, not "every function": the initialization method (if any), event handlers, setTimeout callbacks, etc. Since you're probably already calling non-native methods which wrap those APIs, that method can handle exception log wrapping for you, too.
For example, for event handling I call an internal on(obj, "name", function(){}) method, and on() passes the callback through logExceptions() for me.
But there's no need to wrap every function, just the ones that can be top-level entry points. It's a very small list, if your application is well-designed.
Patch setTimeout and setInterval. Register a jQuery ajax prefilter that wraps all your ajax callbacks. Patch jQuery's low-level UI event binding function.
And you're done. I've done this in a rather large application. It works fine.
Fair enough. I guess that's the pure js/jquery version of hooking into Angular/Ember's onerror. Makes sense. At least we won't need to do this for much longer though.
I didn't say you did. I don't think the size of the app is a factor, either.
This came from a fairly large library which runs on all manner of third-party sites, many billions of times each month. In that situation trapping and logging all exceptions is very important, and this method has worked reliably for years.
Further, you only have to use a logger-wrapped function for your script's entry points, not "every function": the initialization method (if any), event handlers, setTimeout callbacks, etc. Since you're probably already calling non-native methods which wrap those APIs, that method can handle exception log wrapping for you, too.
For example, for event handling I call an internal on(obj, "name", function(){}) method, and on() passes the callback through logExceptions() for me.