Catching silent Javascript exceptions with a function decorator
Posted on August 19, 2008 by Mikko Ohtamaa
Filed Under javascript
The one utterly annoying thing with the otherwise excellent Firefox/Firebug combo is that some exceptions are let silently through without being end up to be visible in the Firebug console. This makes debugging very difficult, unless you are aware of the phenomenon. I am not sure whether this is caused by some internal Firefox logic flow, since IE + Visual Web Developer doesn’t seem to be affected by this.
Since this problem pops up constantly, I decided to create an easy way to deal with the situation. I decorate all functions which made have silent exceptions (e.g. one called from document load event) with a custom logger function which will first log the exception and then rethrow it.
Thus instead of writing (JQuery example)
myfunction() {
// crash here
var i = foobar; // missing variable foobar
}
$(document).ready(myfunction);
write
myfunction() {
// crash here
var i = foobar; // missing variable foobar
}
$document.ready(logExceptions(myFunction));
or
// myFunction can be bind to many events and exceptions are logged always
myfunction = logExceptions(function() {
// crash here
var i = foobar; // missing variable foobar
});
$document.ready(logExceptions(myFunction));
The Javascript code for the decorator:
/**
* Enhancd Javascript logging and exception handler.
*
* Copyright 2008 Red Innovation Ltd.
*
* @author Mikko Ohtamaa
* @license 3-clause BSD
*
*/
// Browser specific logging output initialization
// Supports Firefox/Firebug. Other (Opera) can be hooked in here.
if(!console) {
// Install dummy functions, so that logging does not break the code if Firebug is not present
var console = {};
console.log = function(msg) {};
console.info = function(msg) {};
console.warn = function(msg) {};
} else {
// console.log provided by Firefox + Firebug
}
/**
* Try print human digestable exception stack trace to Firebug console.
*
* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Error
*
* @param e: Error
*/
function printStackTrace(e) {
var msg = e.name + ":" + e.message;
if (e.fileName) {
msg += " at " + e.fileName + ":" + e.lineNumber;
}
console.log(msg);
if (e.stack) {
// Extract Firefox stack information. This tells how you ended up
// to the exception in the first place. I didn't find
// instructions how to parse this stuff.
console.log(e.stack);
}
}
/**
* Decorate function so that exceptions falling through are printed always.
*
* Returns a decorated function which will be used instead of the normal function.
* The decorated function has preplaced try ... catch block which will not let
* through any exceptions silently or without logging. Even though there is an
* exception it is normally throw upwards in the stack after logging.
*
* @param func: Javascript function reference
*/
function logExceptions(func) {
var orignal = func;
decorated = function() {
try {
orignal.apply(this, arguments);
} catch(exception) {
printStackTrace(exception);
throw exception;
}
}
return decorated;
}
Other posts by Mikko Ohtamaa
RSS