Error Pages Phone Home

I always cringe when a customer runs into a problem with their websiteor web application before I do. Because I'm not perfect, my software isn't either, but it's difficult to explain that to a customer when they're staring at a Tomcat stack trace.

JSP error pages are fairly useless for the average user in their default state. Generally the user is greeted with a cryptic number, error message and stack trace that is hardly useful in reaching their goal and they have no choice but to back up and try other options, hunt for the webmaster's email or most likely give up and leave. Software errors while avoidable are bound to occur. In your JSP application there are several things you can do to improve this situation.

First, set-up a custom error page for catching exceptions. Add the following to your web.xml file pointing to a JSP page to handle the error.

<error-page> 	<exception-type>java.lang.Exception</exception-type> 	<location>/error.jsp</location> </error-page> 

It's best to base the error page off the same general design as all your other site pages with a graphic difference to indicate a problem has occured. In Foundation we use a simple stop sign symbol with an exclamation mark. It's important to explain to the user that an error has occurred and it doesn't hurt to add an apology.

It's then best to indicate that the maintainer of the website has been notified of the error and will look into it. Furthermore it's helpful to provide either an email link or a form to allow the user to contact the webmaster or customer support if they require immediate assistance or if they feel they can provide more details.

Now, how do we as the webmaster know the error occurred?

A JSP error page has access to the offending exception. It simply exists within the JSP page as the variable "exception". We can extract the error message and stack trace from the exception to begin to build a simple report detailing the problem that occurred.

StringBuffer sb = new StringBuffer(); // append error message sb.append(exception.getMessage()); sb.append("\n"); // append stack tracce StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); sb.append(sw.toString()); sb.append("\n"); 

Stack traces are great but receiving an error report with a stack trace doesn't do much to tell you what happened at the time the error occurred, so let's dig for some more data.

We would like to know what page the error occurred on. We can retrieve that from the request object.

// append request URL sb.append("Request URL:"); sb.append(request.getRequestURL()); sb.append("\n"); 

Knowing the page is great but page state can be helpful. We can then append all request parameters that accompanied the request.

// append parameters sb.append("Parameters:"); Enumeration enum = request.getParameterNames(); int numValues = 0; while(enum.hasMoreElements()){     	numValues++;     	String name = (String)enum.nextElement();	String value = request.getParameter(name);	sb.append(name);	sb.append(":");	sb.append(value);	sb.append("\n"); } if( numValues == 0 ){     	sb.append("No parameters"); } sb.append("\n"); 

Finally it's helpful to see where the user was coming from by pulling the referrer URL from the request header. Since we're pulling request headers we might as well add them all in the report. Headers include cookie information and what type of browser the user has.

In addition to all this wonderful information you could also add session and page context information if you wished depending on what servlet features your web application utilizes.

Now, how do we notify ourselves when an error occurs? There are many different ways of reporting errors. I find Log4J the simplest. By configuring a simple log4j.properties file and placing it in my root classes folder I can catch all Log4J errors and have them emailed to me via the SMTPAppender.

log4j.appender.mailer=org.apache.log4j.net.SMTPAppenderlog4j.appender.mailer.Threshold=ERROR log4j.appender.mailer.BufferSize=10 log4j.appender.mailer.from=error@domain.com log4j.appender.mailer.SMTPHost=localhost log4j.appender.mailer.subject=Website Name Error log4j.appender.mailer.to=support@support-domain.com log4j.appender.mailer.layout=org.apache.log4j.PatternLayout log4j.appender.mailer.layout.ConversionPattern=%t %-5p %d{dd MMM yyyy HH:mm:ss,SSS} %c{2} - %m%n log4j.logger.com.package=ERROR, mailer 

In the JSP file, log the error using the StringBuffer we created our report with above.

// create the logging category Category cat = Category.getInstance("com.package.jsp.error"); // log error cat.error(sb.toString()); 

Alternatively you could use something like the Jakarta Mail Tag Library to send an email.

The astute readers will note that without the localhost mail server running this plan isn't going to work. I will leave it as an exercise or a later article to devise a strategy for monitoring both client websites and their respective services such as databases and mail servers to ensure all necessary services are always running.

You'll be amazed at how much better your customers will feel when you call them ahead of time to let them know that you noticed a problem and are already taking care of it. Problems occur. But being proactive about as much as you can will go a long way to improving your customer relationship and peace of mind.