Click here to Skip to main content
Email Password   helpLost your password?

Introduction

It's kind of scary realising that should your JavaScript fail, the only way you'll know is if some kind user lets you know. We've all seen "object x is undefined" errors and so on, how many times have you reported the error to the webmaster? It's easy for these problems to go unnoticed for prolonged periods of time.

I have recently been getting to grips with 'AJAX' techniques, and had a magic light-bulb moment when I realised that by using a combination of AJAX and C#, we can do away with reliance on users, and log the errors automatically ourselves.

The basic plan of attack is as follows:

Overview.

Background

The whole concept hinges on catching the errors in the first place, then using XMLHttpRequests to send the error data back to the server via a .NET HTTP handler which finally invokes a method of some kind that does something useful with the error information.

Check out MSDN for more info on catching errors on the client side.

If you haven't used AJAX before, I suggest the following helpful resources:

If you're new to HttpHandlers in .NET, go no further than:

Using the code

The sample ASP.NET (C#) project is pretty straightforward and easy to use (to get the sample code working, simply web-share the JavaScriptErrorLogger folder so that you make HTTP requests to the web server). Let's take a look at the essentials.

The good news is that it's pretty easy to apply the error catching code to existing JavaScripts. To handle errors, all you need to do is handle the Window.Onerror event:

window.onerror = errorHandler;

errorHandler will, of course, point to a function that does something constructive with the event:

function errorHandler(message, url, line)
{
    // message == text-based error description

    // url     == url which exhibited the script error

    // line    == the line number being executed when the error occurred


    // handle the error here

    alert( message + '\n' + url + '\n' + line );
    
    return true;
}

Obviously, your error handling needs to be very reliable. Alerting the error data is not especially ground breaking, so here is the JavaScript used in the sample code which actually executes the XmlHttpRequest:

function errorHandler(message, url, line)
{
    // message == text-based error description

    // url     == url which exhibited the script error

    // line    == the line number being executed when the error occurred


    // handle the error here

    //alert( message + '\n' + url + '\n' + line );

    
    
    //-------------------------------------------------------------------

    // Log the Error

    //-------------------------------------------------------------------

    
    var xmlHttpRequest;
    // a variable to hold our instance of an XMLHTTP object.


    var bHookTheEventHandler = true;
    // used to switch on/off the handling

    // of any response from the server.


    // Checking if IE-specific document.all collection exists 

    // to see if we are running in IE 

    if (document.all)
    { 
        xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP"); 
    } else { 
        xmlHttpRequest = new XMLHttpRequest(); 
    }
    

    //----------------------------------------------------------------        

    // Roll the error information into an xml string:

    //----------------------------------------------------------------

    var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
    xmlDoc.async = false;
    xmlDoc.loadXML("<JavaScriptError line='" + line + "' url='" 
                   + url + "'>" + message + 
                   "</JavaScriptError>");


    //------------------------------------------------------------

    // If you want to see some sort of response to prove (on the 

    // client end) that something has happened,

    // set bHookTheEventHandler = true 

    // otherwise false is probably all we want.

    //------------------------------------------------------------

    if(bHookTheEventHandler)
    {
        xmlHttpRequest.onreadystatechange = 
                sendSomeXml_HandlerOnReadyStateChange;
    }

    //prepare the call, http method=GET, false=asynchronous call

    xmlHttpRequest.open("post", "http://localhost/JavaScript" + 
            "ErrorLogger/logerror.ashx", bHookTheEventHandler);

    //finally send the call

    xmlHttpRequest.send( xmlDoc );  
    
    //------------------------------------------------------------

    // Finished Logging the Error

    //------------------------------------------------------------

                    
    return true;
}

Note that handling the xmlHttpRequest.onreadystatechange event is not necessary if you just want to log errors, but you could use it in this context if you wanted to let the user know that an error has occurred and has been logged.

Before we can catch any incoming requests, we need to tweak the web.config file (see the background links above for more info). The beauty of this approach is that the URL specified when making the XmlHttpRequest doesn't have to actually exist. In this example, the HTTP handler will catch requests for .ashx URLs.

<httpHandlers>
  <!-- Simple Handler -->
  <add verb="*" path="*.ashx" 
        type="JavaScriptErrorLogger.LogErrorHandler, JavaScriptErrorLogger" />
</httpHandlers>

On the server side, we'll catch the incoming XML using an HTTP handler:

using System;
using System.Web;
using System.Xml;

namespace JavaScriptErrorLogger 
{

    public class LogErrorHandler : IHttpHandler 
    {

        public void ProcessRequest( HttpContext httpContext ) 
        {
            XmlDocument xmlDoc = null;
        
            // If XML document was submitted via POST method

            // then load it in the DOM document:

            if (httpContext.Request.InputStream.Length > 0 && 
                httpContext.Request.ContentType.ToLower().IndexOf("/xml") > 0) 
            {
                xmlDoc = new XmlDocument();
                xmlDoc.Load( httpContext.Request.InputStream );
        
                // at this point the XML message is available via xmlDoc.InnerXml: 

                Console.WriteLine( xmlDoc.InnerXml );
            }
        }
    }
}

Most of the examples I have found on the net make the client side XmlRequest using GET. If you want to send data to the server, you'll need to POST it (as in the error handling code provided earlier). Having used POST, we can get the data sent to the server by using httpContext.Request.InputStream (as above). In this example, we are simply outputting the XML to the console, where as in the sample code, we use a method that will log the XML to a file.

Having caught the XML in our HTTP handler, we could send it (or other XML) back out again:

public void ReturnXML( HttpContext httpContext, string rawXml )
{
    if(rawXml == "")
        throw new ApplicationException("The value of rawXml was not defined.");

    // Produce XML response:

    httpContext.Response.ContentType = "application/xml";
    XmlTextWriter xw = new XmlTextWriter( httpContext.Response.OutputStream, 
                                           new System.Text.UTF8Encoding() );
    xw.WriteRaw( rawXml );
    xw.Close();
}

Points of Interest

You will see in the sample code that I use a simple object to pass the error information about (at the C# level). This object has only one property (a string) which contains the XML that describes the error. But being clever, you'll realize that this could be extended to include any other info we want to send with the error, such as the client's browser and so on. You could go further and deserialize the XML straight into a C# object.

Since - in an ideal world - you'll never get any errors, it will be wise to construct a test-harness so you can periodically invoke an error and check that it is processing the errors just as you intend it to. If your system hasn't send you any error logs for a while, it'd be best if that was because there weren't any - not because the error handling is broken.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNew Server Control to log JavaScript Errors
ghmcadams
9:26 2 Feb '10  
I have just released code to help log JavaScript errors by sending error information to the server - http://www.thecodepage.com/post/JavaScript-Error-Notifications.aspx[^]

www.thecodepage.com

GeneralRe: New Server Control to log JavaScript Errors
Adrian K
11:10 5 Feb '10  
Awesome - I haven't looked at your code yet, but anything that makes logging client-side errors easier has to be a good thing Smile
Generalyou be the man
cpbrand
5:29 15 Apr '09  
thanks!

Ian

GeneralHow to get error message from server using AJAX.
SANDESHDADDI
23:30 15 Jan '07  
I am doing project where i m firing a query on database.
i am sending request by XMLHttpRequest object

I want to display an error message when there will be an error in executing that query. But my server is always returning me true(Query fired ok) response.


Then how do i receive error message on client side?

Thank you
GeneralURGENT HELP PLS
ab6284
2:53 2 Jan '07  
Trapping Java script errors in Mozilla Firefox?
in mozilla firfox, how to trap javascript errors on page load, and write the error and url into a TEXT FILE... is there any solution to this using extensions? how else can it be done? how to use event handlers in mozilla? is that a possible solution, if yes, how to implement...

Questionwhere the error javascript
zhaojicheng
20:43 21 Jun '06  
In you app there isnnt in it.you had better upload it in the demo.
Thanks
AnswerRe: where the error javascript
zhaojicheng
21:09 21 Jun '06  
logerror.ashx?
I cannt find it.
AnswerRe: where the error javascript [modified]
Adrian K
0:06 25 Aug '06  
Hi Zhao,

Sorry for taking so long to respond to you.

There isn't an actual logerror.ashx file, instead have a look in the web.config:

      <httpHandlers>
         <!-- Simple Handler -->
         <add verb="*" path="*.ashx" type="JavaScriptErrorLogger.LogErrorHandler, JavaScriptErrorLogger" />
      </httpHandlers>

The http handler recognises any .ashx request and pipes it to the JavaScriptErrorLogger.LogErrorHandler class where the actual error logging is initiated.

On a related note, you can be more specific when matching requests to classes, such as in this example:

<httpHandlers>
   <add verb="*" path="Search.ashx" type="MyApp.Assembly1.HttpHandlers.SearchHelper, MyApp.Assembly1" />
   <add verb="*" path="Preview.ashx" type="MyApp.Assembly1.HttpHandlers.Preview, MyApp.Assembly1" />
   <add verb="*" path="PopulateDropDown.ashx" type="MyApp.Assembly2.HttpHandlers.Populate, MyApp.Assembly2" />
</httpHandlers>



-- modified at 5:14 Friday 25th August, 2006
GeneralRe: where the error javascript
zhaojicheng
18:02 27 Aug '06  
Yeah.I already run it.Thanks very useful code for me. thanks
QuestionMissing JavaScript
RainyDaysInVancouver
20:08 6 Jun '06  
Hello,

Interesting project. But where is the JavaSript in the .htm file?

Thanks

I downloaded the project but there's no JavaScript?

AnswerRe: Missing JavaScript [modified]
Adrian K
0:13 25 Aug '06  
Hi Van,

Sory for the delayed responseFrown

Hmmm - good question. Doh!
All you need to add is the folling line to catch the window.onerror event.

window.onerror = errorHandler;

errorHandler is the name of the function you want to use to handle errors.
For a start, try using the main/larger "function errorHandler(message, url, line)" example in the article.


-- modified at 5:14 Friday 25th August, 2006
GeneralThis script works for both FireFox and IE just thought it would be helpful!
darthtim2004
9:54 8 May '06  
<script type="text/javascript">
window.onerror = errorHandler;
function errorHandler(message, url, line)
{
alert('errorHandler input values\nMessage: ' + message + '\nURL: ' + url + '\nLine: ' + line);
try
{
// JavaScript Browser Sniffer (edited)
// Eric Krok, Andy King, Michel Plungjan Jan. 31, 2002
// see http://www.webreference.com/ for more information
// taken from
var agt = navigator.userAgent.toLowerCase();
//alert('agt= ' + agt);

var appVer = navigator.appVersion.toLowerCase();
//alert('appVer= ' + appVer);

var iePos = appVer.indexOf('msie');
//alert('iePos= ' + iePos);

var is_opera = (agt.indexOf("opera") != -1);
//alert('is_opera= ' + is_opera);

var is_mac = (agt.indexOf("mac")!= -1);
//alert('is_mac= ' + is_mac);

var is_konq = (agt.indexOf('konqueror') != -1);
//alert('is_konq= ' + is_konq);

var is_getElementById = (document.getElementById) ? "true" : "false"; // 001121-abk
//alert('is_getElementById= ' + is_getElementById);

var is_getElementsByTagName = (document.getElementsByTagName) ? "true" : "false"; // 001127-abk
//alert('is_getElementsByTagName= ' + is_getElementsByTagName);

var is_documentElement = (document.documentElement) ? "true" : "false"; // 001121-abk
//alert('is_documentElement= ' + is_documentElement);

var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
//alert('is_safari= ' + is_safari);

var is_khtml = (is_safari || is_konq);
//alert('is_khtml= ' + is_khtml);

var is_gecko = ((!is_khtml)&&(navigator.product)&&(navigator.product.toLowerCase()=="gecko"))?true:false;
//alert('is_gecko= ' + is_gecko);

var is_fb = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1) &&
(agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1) &&
(agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1) &&
(is_gecko) && (navigator.vendor=="Firebird"));
//alert('is_fb= ' + is_fb);

var is_fx = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1) &&
(agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1) &&
(agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1) &&
(is_gecko) && ((navigator.vendor=="Firefox")||(agt.indexOf('firefox')!=-1)));
//alert('is_fx= ' + is_fx);

var is_moz = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1) &&
(agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1) &&
(agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1) &&
(is_gecko) && (!is_fb) && (!is_fx) &&
((navigator.vendor=="")||(navigator.vendor=="Mozilla")||(navigator.vendor=="Debian")));
//alert('is_moz= ' + is_moz);

var is_nav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)
&& (!is_khtml) && (!(is_moz)) && (!is_fb) && (!is_fx));
//alert('is_nav= ' + is_nav);

var is_ie = ((iePos!=-1) && (!is_opera) && (!is_khtml));
//alert('is_ie= ' + is_ie);

// message == text-based error description
// url == url which exhibited the script error
// line == the line number being executed when the error occurred
// handle the error here
//alert( message + '\n' + url + '\n' + line );
//-------------------------------------------------------------------
// Log the Error
//-------------------------------------------------------------------
var xmlHttpRequest;
// a variable to hold our instance of an XMLHTTP object.
var bHookTheEventHandler = true;
// used to switch on/off the handling
// of any response from the server.
// Checking if IE-specific document.all collection exists
// to see if we are running in IE
// improved code to run in all browsers
if (window.XMLHttpRequest)
{
//alert('xmlHttpRequest');
xmlHttpRequest = new XMLHttpRequest();
}
else
{
try
{
//alert('before try');
xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
//alert('after try');
}
catch(e)
{
//alert('AJAX not Supported so JavaScritErrorLogging Failed for Error:\nMessage: ' + message + '\nURL: ' + url + '\nLine: ' + line);
}
}
//----------------------------------------------------------------
// Roll the error information into an xml string:
//----------------------------------------------------------------
var output = '\nMessage=' + message + '\n';
output = output + 'agt=' + agt + '\n';
output = output + 'appVer=' + appVer + '\n';
output = output + 'iePos=' + iePos + '\n';
output = output + 'is_opera=' + is_opera + '\n';
output = output + 'is_mac=' + is_mac + '\n';
output = output + 'is_konq=' + is_konq + '\n';
output = output + 'is_getElementById=' + is_getElementById + '\n';
output = output + 'is_getElementsByTagName=' + is_getElementsByTagName + '\n';
output = output + 'is_documentElement=' + is_documentElement + '\n';
output = output + 'is_safari=' + is_safari + '\n';
output = output + 'is_khtml=' + is_khtml + '\n';
output = output + 'is_gecko=' + is_gecko + '\n';
output = output + 'is_fb=' + is_fb + '\n';
output = output + 'is_fx=' + is_fx + '\n';
output = output + 'is_moz=' + is_moz + '\n';
output = output + 'is_nav=' + is_nav + '\n';
output = output + 'is_ie=' + is_ie + '\n';
output = output + '
' + '\n';

//alert('var xmlDoc');
var xmlDoc;
if (document.implementation && document.implementation.createDocument)
{
alert('firefox');
xmlDoc = document.implementation.createDocument("","",null);
alert(xmlDoc);
alert('xmlDoc.async = false;');
xmlDoc.async = false
alert('Before: xmlDoc.load(output); = ' + xmlDoc);
xmlDoc = new DOMParser().parseFromString(output, 'text/xml');
alert('after: xmlDoc.load(output);= ' + xmlDoc);
}
else
{
try
{
//alert('IE');
if (window.ActiveXObject)
{
xmlDoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
//alert('xmlDoc.async = false;');
xmlDoc.async = false;
//alert('Before: xmlDoc.loadXML(output);');
xmlDoc.loadXML(output);
//alert('after: xmlDoc.loadXML(output);');
}
}
catch(e)
{
alert('xmldoc not Supported so JavaScritErrorLogging Failed for Error:\nMessage: ' + message + '\nURL: ' + url + '\nLine: ' + line);
}
}

//------------------------------------------------------------
// If you want to see some sort of response to prove (on the
// client end) that something has happened,
// set bHookTheEventHandler = true
// otherwise false is probably all we want.
//------------------------------------------------------------
//alert('bHookTheEventHandler');
//if(bHookTheEventHandler)
//{
// alert('before xmlHttpRequest.onreadystatechange = sendSomeXml_HandlerOnReadyStateChange;');
// alert('sendSomeXml_HandlerOnReadyStateChange: ' + sendSomeXml_HandlerOnReadyStateChange);
// xmlHttpRequest.onreadystatechange = sendSomeXml_HandlerOnReadyStateChange;
// alert('after xmlHttpRequest.onreadystatechange = sendSomeXml_HandlerOnReadyStateChange;');
//}
//prepare the call, http method=GET, false=asynchronous call
alert('xmlHttpRequest.open' + xmlDoc);
xmlHttpRequest.open("post", "http://localhost:3456/JavaScriptErrorLogger/logerror.ashx", bHookTheEventHandler);
//finally send the call
//alert('xmlHttpRequest.send');
xmlHttpRequest.send(xmlDoc);
alert('after send');
//------------------------------------------------------------
// Finished Logging the Error
//------------------------------------------------------------
}
catch(e)
{
alert(e.Message);
throw(e);
}
return true;
}
</script>
GeneralURGENT HELP PLS
ab6284
2:49 2 Jan '07  
Trapping Java script errors in Mozilla Firefox?
in mozilla firfox, how to trap javascript errors on page load, and write the error and url into a TEXT FILE... is there any solution to this using extensions? how else can it be done? how to use event handlers in mozilla? is that a possible solution, if yes, how to implement...

GeneralRe: This script works for both FireFox and IE just thought it would be helpful! - URGENT HELP REQUIRED
ab6284
18:58 2 Jan '07  
Hi,
I needed to develop a plug in or something similar for FIREFOX that would detect javascrist errors on page load and log into a file...
can i use your code for that?
can you tell me where i should put this code for the functionality i need?
It should start up when i open the browser only, without me having to trigger, it should log any js errors it comes across on page load...
PLEASE HELP.
GeneralRe: This script works for both FireFox and IE just thought it would be helpful!
ab6284
20:26 2 Jan '07  
hey can you tell me how to trigger a js script when a javascript error occurs on page load in FIREFOX? when there's an entry in the error console, i want it to auto trigger a script... how do i do that? any clue?
GeneralAjax Projects
Hazem Torab
12:00 4 Jan '06  
AjaxProjects.com is a new directory...

Here you are...

This site will help you to find all the resource to learn and know all about Ajax technology, by providing you with the latest Ajax projects, latest Ajax tutorial, Ajax articles, Ajax Forum and Ajax news.


I found this portal, it's about ajax technology it represents all the projects that implemented using ajax technology, and libraries that may help in creating ajax projects
http://www.ajaxprojects.com
Hazem Torab

Hazem TOrab
GeneralMissing Files
DrewM
5:32 21 Dec '05  
The solution you included in the article is missing 2 files - WebForm1.aspx and HTMLPage1.htm.

Otherwise, nicely done.
GeneralRe: Missing Files
Adrian K
14:09 21 Dec '05  
Hi Drew,

Thanks for the positive feedback Smile

WebForm1.aspx is not included because it's not needed.
The whole idea is that it doesn't need to be an ASP.NET web app generating the errors - ASP.NET is only involved in receiving the error messages.

Funny really - you could start up a business that hosted error recieving functionality and "static" html websites could sent their errors to you - for a small fee.

I used default.htm (instead of HTMLPage1.htm) out of habit - IIS is configured to serve default.htm by default, otherwise you'd have to request HTMLPage1.htm specifically Smile

Adrian K
GeneralRe: Missing Files
RainyDaysInVancouver
17:35 4 Jun '06  
Hello,

Interesting project. But where is the JavaSript in the .htm file?

Thanks
QuestionRemarks . . .
Aur3lien
3:43 13 Dec '05  
Why do you test XmlHttpRequest Implementation ?

Actually, this only works for gecko based browser and those browsers won't go throught the next line with DOMDocument implementation because they cannot instantiate ActiveXObject ...
Using this script with gecko based browsers will run in an infinite loop on the errorHandler because ActiveXObject is undefined ...

What about syntax Errors ?

Let's take an example :
<html> <head> <script type="text/javascript"> errorHandler = function(message, url, line)
{
alert( message + '\n' + url + '\n' + line );
return true;
}
window.onerror = errorHandler;
var xmlDoc = ;
</script> </head> <body> </body> </html>

Syntax Errors will block the script engine and never go in the errorHanlder process to get that error back ...

By the way, nice article on logging errors to server when they're not syntax one or not gecko browser based Smile

PS: Why not using document.implementation.createDocument for Gecko based browser to create the Xml Stream ?

Aurelien
MVP ASP/ASP.Net (France)
AnswerRe: Remarks . . .
Adrian K
13:16 13 Dec '05  
Thanks for your comments Aurelien Smile

If I have understood you first question correctly - that fist example (the one you have included) is just a simple example for anyone not familiar with catching client-side JavaScript errors.

Unfortunately I'm an absolute novice regarding cross-browser support, but hopefully that will improve overtime (particularly with such good feedback) Smile
I guess that once I have proved a concept in MSIE, I can then increase the scope of the idea to include a wider range of browsers.

Smile
Adrian K
GeneralNo document.all check please!
Albert Weinert
2:30 13 Dec '05  
Please, don't check vor document.all for the IE check.

You do.
if (document.all)
{
xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
} else {
xmlHttpRequest = new XMLHttpRequest();
}

IE 7 will have document.all and a native XMLHttpRequest() object without Active X. Also newer Versions of Firefox are supporting document.all. So your code will fail if Active X is disabled in IE 7, or if a browser Supports document.all and no ActiveX.

you should use something like this.

if (window.XMLHttpRequest)
{
xmlHttpRequest = new XMLHttpRequest();
} else
{
try {
xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e)
{
alert('AJAX not Supported');
}
}


Regards
Der Albert
GeneralRe: No document.all check please!
Adrian K
13:19 13 Dec '05  
Thanks Der Albert,

I had simply been coping examples from MSDN.
Your approach is definately better, once the article has been up for a bit longer and reviewed by more people I will include you're/their suggections and update the article.

Cheers,
Adrian K
General500 Error
Yazeed hs
1:00 13 Dec '05  
Hi,

I have a web service that is consumed from the client side i.e. using Java Script XmlHttpRequest object . It works fine on the local machine but doesn't work on remote machines. On remote machines, I'm getting 500 "Internal Server error". I suspect that I need to configure IIS to allow access to the Web Service. But since its working on the local machine and not on remote machines, I'm not sure how to grant access specifically for this web service. I'm allowing anonymous access to my application.

can anyone help me out on this one.

GeneralRe: 500 Error
Adrian K
13:54 13 Dec '05  
500 "Internal Server error"
isn't very specific and therefore not particularly helpful Smile Do you have any logging or exception handling in place? The more you can find out about the error the easier it will be to fix.


Last Updated 12 Dec 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010