Click here to Skip to main content
15,896,111 members
Articles / Web Development / HTML

Logging Client Side JavaScript Errors to the Server

Rate me:
Please Sign up or sign in to vote.
4.29/5 (10 votes)
12 Dec 20054 min read 146.8K   447   66  
How to log client side JavaScript errors to the server using AJAX, XML and C#.
using System;
using System.Web;
using System.Xml;


namespace JavaScriptErrorLogger 
{

	#region ...   The HttpHandler Class that will handle our AJAX Requests   ...

	public class LogErrorHandler : IHttpHandler 
	{
		private SpecificRequestHandlers _SpecificRequestHandlers = new SpecificRequestHandlers();

		public bool IsReusable 
		{
			get 
			{
				return true;
			}
		}
    
		public void ProcessRequest( HttpContext httpContext ) 
		{
			XmlDocument xmlDoc = null;
			int numberOfWidgetsToMake = 0;
			JavaScriptErrorLogger.ErrorEntity errorEntity;


			// 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 );


				//--------------------------------------------------------
				// Log the error...
				//--------------------------------------------------------
				JavaScriptErrorLogger.PhysicalLogging.LogErrorAsTextFile( new ErrorEntity( xmlDoc.InnerXml ) );


//				//--------------------------------------------------------
//				// ...or long-hand for clarity:
//				//--------------------------------------------------------
//				
//				// Get the xml that we sent through using an 'AJAX' request:
//				string javaScriptErrorRawXml = xmlDoc.InnerXml;
//
//				// Roll the xml data into an ErrorEntity object: 
//				errorEntity = new ErrorEntity( javaScriptErrorRawXml );
//
//				// Pass the ErrorEntity into the desired PhysicalLogging method
//				// to actually save the error info:
//				JavaScriptErrorLogger.PhysicalLogging.LogErrorAsTextFile( errorEntity );

				// Send the error information back to the calling 'AJAX' request, just for fun:
				_SpecificRequestHandlers.ReturnXML( httpContext, xmlDoc.InnerXml );
			}


			// Decide what to do based on querystring:
			if(httpContext.Request.QueryString["c"] != null)
			{
				if(httpContext.Request.QueryString["c"].ToString() != "")
				{
					numberOfWidgetsToMake = int.Parse( httpContext.Request.QueryString["c"].ToString() );
				}
			}

			if(numberOfWidgetsToMake > 0)
			{
				_SpecificRequestHandlers.SendXmlResponseForGetXML( httpContext, numberOfWidgetsToMake );
			}

		}


	}

	#endregion


	#region ...   Classes / Methods to handle specific requests   ...

	public class SpecificRequestHandlers
	{
		public void SendXmlResponseForGetXML( HttpContext httpContext, int numberOfWidgetsToMake )
		{
			// Check pre processing conditions:
			if(numberOfWidgetsToMake < 5)
			{
				numberOfWidgetsToMake = 5;
			}

			// Produce XML response:
			httpContext.Response.ContentType = "application/xml";
			XmlTextWriter xw = new XmlTextWriter( httpContext.Response.OutputStream, new System.Text.UTF8Encoding() );

			xw.WriteStartElement("Widgets");

			for(int c = 0; c < numberOfWidgetsToMake; c++)
			{
				xw.WriteStartElement("Widget");
				xw.WriteAttributeString("Created", DateTime.Now.ToString() );
				xw.WriteAttributeString("WidgetIndex", c.ToString() );
				xw.WriteString( string.Format("I am widget {0}.", c) );
				xw.WriteEndElement(); // Widget
			}

			xw.WriteEndElement(); // Widgets

			xw.Close();
		}


		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();
		}
	}
	
	#endregion


	#region ...   Generic entity objects   ...

	/// <summary>
	/// Generic entity object for the transportation of 
	/// error data between different tiers of the application.
	/// </summary>
	public struct ErrorEntity
	{
		public ErrorEntity( string message ) 
		{
			this._Message = message;
		}

		private string _Message;
		public string Message
		{
			get{ return this._Message; }
		}

		public override string ToString()
		{
			return string.Format("{0}", _Message);
		}
	}

	#endregion


	#region ...   Physical logging of the error   ...

	/// <summary>
	/// Handles the saving of error log information to 
	/// some sort of persistant data storage system.
	/// </summary>
	public class PhysicalLogging
	{
		public static void LogErrorAsTextFile( ErrorEntity errorEntity ) 
		{
			// Create an instance of StreamWriter to write text to a file.
			// The using statement also closes the StreamWriter.
			using (System.IO.StreamWriter sw = System.IO.File.CreateText( string.Format(@"{0}JavaScriptError_{1}.txt", AppDomain.CurrentDomain.BaseDirectory, TimeStamp()) )) 
			{
				sw.Write( errorEntity.ToString() );
			}
		}

		private static string TimeStamp()
		{
			return string.Format("{0}.{1}.{2}-{3}.{4}.{5}-{6}", 
				DateTime.Now.Year.ToString(),
				DateTime.Now.Month.ToString(),
				DateTime.Now.Day.ToString(),
				DateTime.Now.Hour.ToString(),
				DateTime.Now.Minute.ToString(),
				DateTime.Now.Second.ToString(),
				DateTime.Now.Millisecond.ToString());
		}
	}

	#endregion

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Morphological Software Solutions
New Zealand New Zealand
Mild mannered Solutions Architect by day, .Net CMS/web-app framework developer by night.

For the CMS/Framework check-out: http://www.morphological.geek.nz and/or morphfolia.codeplex.com

I blog: www.morphological.geek.nz/blogs/PeruseMuseInfuse.aspx

And you can also find me on LinkedIn: www.linkedin.com/in/adriankearns

Comments and Discussions