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.