Friday, December 18, 2009

ScriptCanary's Client-Side Error Handling Code

Here's a detailed walk-through of the ScriptCanary client code.
 
The first thing we're doing here is attaching an event handler to the Window.Onerror event.
 
The handler's tasks are simple:
 
1) Grab a few lines of the erroneous source code if possible.
2) Send the source code and other details of the error report to the ScriptCanary web service. 
 
At the very top of the script we have:
 
onerror =   // assign our own handler to the Window.onerror event
function(d, p, l) // d: Error Description; p: Path; l: Line
{

Next, we make the standard bare-Javascript moves to get the XMLHTTPREQUEST object:

    try
    {
        R = new XMLHttpRequest();
    }
    catch (E)
    {
        try
 
...et cetera. Next, we see why we need the XMLHTTP object.

We're going to attempt to do a synchronous read of the problem source code file and grab the exact source lines as they appear at this moment.

This guarantees that the lines will be available when it's time to view the error, and won't cause cross-site access errors when the user is reviewing the bug details later.

R.open("GET", p, true);
R.onreadystatechange =
function()
{
    if (R.readyState == 4)
    {
        if (R.status == 200)
        {
            // Split the file into an array of lines.
            A = R.responseText.split(new RegExp("(\r\n){1}"));
 
            // Find only the lines around the error,
            // and insert the line numbers            
            for (i = 0; i < A.length; i++)
                if (i > l - 4 && i < l + 2)
                s += (i + 1) + ': ' + A[i] + "\n";
        }
    }
}
R.send(null);


Now we can send the log entry via a simple fire-and-forget GET request on a new Image object.

NOTE!! ScriptCanary will only log requests from registered customers.

new Image().src =
"http://scriptcanary.com/log.aspx?" +
   // Error Description
   "&d=" + encodeURIComponent(d) +
   // Error Line #
   "&l=" + l +
   // User Agent
   "&u=" + encodeURIComponent(navigator.userAgent) +
   // OS/Device
   "&o=" + encodeURIComponent(navigator.platform) +
   // URL
   "&p=" + encodeURIComponent(p) +
   // ScriptCanary version number
   "&v=1" +
   // Source code (note this can be truncated by the browser to the max url length)                        
   "&s=" + encodeURIComponent(s);    

Finally, disable our error handler. Subsequent errors tend to be noise -- cascading effects from the first problem.
    
 onerror = null;
 
 
Huge thanks go out to Eric Lawrence for his help with this script. 
 
Please send along questions and feedback in the comments, or through our feedback form on ScriptCanary.com.
 
Coming soon: The less-is-more version of the ScriptCanary client code -- only 204 bytes of pure sizzle! 
 
 

0 comments:

Post a Comment