Quality Reads

Sunday, August 26, 2007

Client-Side Error Logging

If you've done any amount of server-side scripting (CF, PHP, RoR, .NET, etc.), you already know the benefits of error handling. It allows you to capture unusual, sometimes unforeseen, errors that can occur in your script and handle them gracefully so your users get proper feedback on what just happened. No matter how great a programmer your are, something out of your control will break your code. Its your responsibility to build in a safety net so your users don't break their neck when they step off the correct path.

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:
  1. 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.
  2. 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.
  3. Lastly, the onError function returns true so the browser knows to disregard the error.
Can you just show the syntax for use? No prob.



<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>

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.

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

Thursday, August 23, 2007

Add A Blog Search Feed to Google Reader

If you're like me your Google Reader RSS Feed Reader is filled with great blogs site ( Lifehacker, Mashable, Techmeme, etc.) While I'm not ditching any of my favorite web filters, sometimes I want to get my information direct from the source, or just another source. Here's a handy trick to keep you ahead of the curve.

Go to Google's Blog Search. Note the RSS/ATOM links on the side. Toss those in your Feed Reader and you're ready to go.

Oh, did I say this was difficult and time consuming? Definitely not.

Very useful? You know it.

Cheers,
Todd

PS - Depending on the search query, you may run into some spam. Play around w/ the advanced search options to get things working right.

Tuesday, August 21, 2007

Got Some Free Time?

Great list of top notch Flash sites: http://flashprayer.blogspot.com/

Steer clear during work hours...lest your lose your whole day (which may or may not be a good thing).

:)

Cheers,
Todd

PS - AIR Tour on Friday in Boston.

Monday, August 13, 2007

Designer//Slash//Model



Simply awesome.


Enjoy!


Check out the source.

Tuesday, August 07, 2007

Code Highlighting


If you're in the market for a code highlighter, I just ran into a good one that handles PHP, Java, Javascript, Perl, SQL, HTML, and CSS. To rock this on your blog/website, all you need to do is include the javascript source in you page header and add a textarea tag like so:


<textarea id="myCpWindow" class="codepress javascript linenumbers-off">
// your code here
</textarea>

Notice the language to be highlighted is included in the class declaration. There's a couple other useful features (such as copying code to the user's clipboard) that can be found here. To make life even easier, I've written up a quick ColdFusion custom tag to create the textarea declaration and include the appropriate content (sorry, non-CF users). Here's the code:


<CFSETTING enablecfoutputonly="true">
<CFIF ThisTag.ExecutionMode eq "Start">
<cfparam name="attributes.language" type="string"><!--- Language to Highlight --->
<cfparam name="attributes.file" type="string"><!--- relative file path --->
<cfparam name="attributes.readOnly" type="boolean" default="false">
<cfparam name="attributes.lineNumbers" type="boolean" default="true">
<cfparam name="attributes.autoComplete" type="boolean" default="false">

<cfset attriList = "language,file,readOnly,lineNumbers,autoComplete">
<cfset attriKey = StructKeyList(attributes)>

<CFTRY>
<CFFILE action="read"
file="#ExpandPath(attributes.file)#"
variable="fileResult">

<CFCATCH type="any">
<CFTHROW detail="Double check the file location. The error occurred trying reading the specified filed.">
</CFCATCH>
</CFTRY>

<CFOUTPUT><textarea class='codepress</CFOUTPUT>
<CFIF attributes.readOnly><CFOUTPUT> readonly-on </CFOUTPUT></CFIF>
<CFIF NOT attributes.lineNumbers><CFOUTPUT> linenumbers-off </CFOUTPUT></CFIF>
<CFIF NOT attributes.autoComplete><CFOUTPUT> autocomplete-off </CFOUTPUT></CFIF>
<CFOUTPUT>'</CFOUTPUT>
<CFLOOP from="1" to="#ListLen(attriKey)#" index="aIndex">
<CFIF NOT ListFindNoCase(attriList, ListGetAt(attriKey,aIndex))>
<CFOUTPUT> #ListGetAt(attriKey,aIndex)#='#attributes[ListGetAt(attriKey,aIndex)]#' </CFOUTPUT>
</CFIF>
</CFLOOP>
<CFOUTPUT>>#fileResult#</textarea></CFOUTPUT>

</CFIF>
<CFSETTING enablecfoutputonly="false">


You can use the tag like so:


<cf_syntaxify <-- whatever you name the tag -->
language="ColdFusion"
file="test.cfm"
id="testID" />


Any attribute you define in the tag that is not param'ed at the top of the custom tag will be passed onto the <textarea> tag. Note the id attribute in the above example.

There are a couple other code highlighters available, most notably the one released by Google, but the simplicity of CodePress is immediately apparent once you check out the docs. Let me know if you run into any problems w/ the custom tag (I haven't tested it extensively yet).

Cheers,
Todd

Friday, August 03, 2007

The Cross-Over Point AKA FU Money

Hackzine has a great post on money management. They discuss the often sought after (little talked about) situation known as FU Money. The point where you earn more in interest on your investments than you spend in living expenses. Its a really simple concept that most people don't think about until they're old and gray (Hackzine begs to differ).

I've come up with a new response to "What's fueling this whole Web 2.0 frenzy?" FU Money, obviously!

Have a great weekend.

Cheers,
Todd

CF8 Logos...


Rey Bango just posted a bunch of CF8 logos. If you're working on a ColdFusion 8 powered project (I know I am), then you may want to snag one of these. I'm hoping to have some info on my *hush* *hush* AIR derby project by Monday.

Cheers,
Todd