Since most developers would generally agree with my sentiment, why don't you see AJAX applications properly handling and logging client-side errors. The application that sticks out for me is Gmail. At least once a week I'll see a host of non-fatal errors pop up. Why? Can't errors that bubble up to the application scope be captured? Yes.
Be better than Google. Here's how:
var ErrorLogger = Class.create();
ErrorLogger.prototype = {
initialize: function(url, opts){
this.url = url;
this.active = true;
this.opts = opts;
window.onerror = this.onError.bind(this);
},
onError: function(msg, URI, line){
try{
if(this.active){
var body = 'URI=' + escape(URI) + '&line=' + line + '&msg=' + escape(msg) + '&brw=' + escape(Object.toJSON(Prototype.Browser)) + '&pv=' + escape(Prototype.Version);
if('onError' in this.opts)this.opts.onError.apply(this, arguments);
var opts = {
onSuccess : this.onSuccess.bind(this),
onFailure : this.onComplete,
postBody : body
};
new Ajax.Request(this.url, opts);
}
}catch(e){
this.onFailure();
}
return true;
},
onSuccess: function(){
if('onSuccess' in this.opts)this.opts.onSuccess.apply(this, arguments);
},
onFailure: function(){
this.active = false;
if('onFailure' in this.opts)this.opts.onFailure.apply(this, arguments);
}
};
What's it doing? Well, first off this is a Prototype Class so you need to include prototype.js in order to use it. Here's the breakdown:
- The window.onerror event is set to call ErrorLogger.onError. When an unhandled error bubbles up to the window scope, onError will be called to handle it.
- Three arguments are passed into the onError function ( msg, URI, line ) and an Ajax request with some additional browser information is constructed and posted to the URL specified in the constructor.
- Lastly, the onError function returns true so the browser knows to disregard the error.
When you click on the button labeled "Throw Error", the ErrorLogger class will gracefully handle the error and post some useful debug information to your server. From there you can do whatever you want. Personally, I just toss it in a log file that I monitor. All that in less than 1KB, not bad.
<html>
<head>
<title>Logger Test</title>
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="ErrorLogger.js"></script>
<script type="text/javascript">
var er;
var init = function(){
er = new ErrorLogger('TestResult.html',
{
onSuccess : function()
{
$('btn').setStyle({'backgroundColor' : 'red'});
},
onError : function()
{
alert('An error occurred on the page. Run for your life!');
}
});
};
</script>
</head>
<body onload="init()">
<button id="btn" onclick="nonExistentFunction()">Throw Error</button>
</body>
</html>
I've tested it on IE6/7 and FF2. Its definitely not production ready quite yet but I'll throw an update up with my final version in a day or two.
Cheers,
Todd