5
votes

I have a medium-size Java Web-application using Log4J as logging-framework. Right now i am going through my Exception handling and Logging to make my application more robust. It is running on Tomcat 6, with spring, hibernate and Struts2 as frameworks.

What I would like to do is to log EVERY UNHANDLED exception that happens in the application. So that i can log them, make log4j send me an email, and then see where i am missing try-catch blocks. And finally modify my code accordingly.

Cause right now all the unhandled exceptions is printed direct to the screen, and my users usally do not bother to copy me the exceptions.

I know i can read tomcat-logs, but i would like to have them handled by log4j so that i can get an email on every such exception.

Any suggestions?

2
You should strive towards NOT HANDLING exceptions anywhere except at a single place in your code -- the so-called exception barrier. This is very much achievable for a web app. You need to wrap every call into your controller code with a try-catch. The same would go for hibernate transaction handling.Marko Topolnik
Well, there are exceptions (pun intended) to the above rule where you might want to catch specific exceptions as part of the application logic. A simple example could be converting a text input to a number, where you do not want your application to crash due to invalid input. I do whole-heartedly agree with the exception barrier for unhandled exceptions though.erikxiv
@MarkoTopolnik No need to wrap every controller invocation in a try-catch when there's declarative means to catch exceptions in both the Servlet spec and Struts2 (maybe even Spring, no idea). Also gets you a single place to handle exceptions, but with much less boilerplate all over the code.Philipp Reichart
@PhilippReichart Exactly, that' what I was really aiming for, but not familiar enough with Struts. Familiar with Spring, though -- piece of cake there and very customizable. I meant that there is a single piece of code inside which the controller invocation takes place.Marko Topolnik
@MarkoTopolnik I absolutely agree with you :) Struts2 does the try-catch around the action/controller invocation for you already, so you only have to tell it what to do for what Exception class.Philipp Reichart

2 Answers

5
votes

With Struts2, you can define global exception mappings for specific Exception types. If you define one for java.lang.Exception it acts as a catch-all for any exception not mapped elsewhere:

<global-exception-mappings>
  <exception-mapping exception="com.example.MyException result="myError" />
  <exception-mapping exception="java.lang.Exception" result="error" />
</global-exception-mappings>

<global-results>
  <result name="myError">/myError.jsp</result>
  <result name="error">/error.jsp</result>
</global-results>

In your error JSPs (*), you can then log them with log4j and give your users a nice "Something went wrong" error page without confronting them with confusing stacktraces.

(*) better: An error action where you can log the exception and only then let Struts render a JSP where you tell the user that something went wrong. No need to clutter JSPs with logging code.

About modifying all your code:

Don't blindly add catch blocks all over your code -- if some piece of code can't handle an exception, just let it propagate (adding a throws clause on the method signature if necessaty). At certain levels in the stack, consider wrapping the thrown Exception and adding some information to help identifying the cause and rethrow it:

 catch (IllegalArgumentException ex) {
    // Always pass the original exception along, never just the message.
    // It's much easier to find the root cause that way.
    throw new UpdateException("Failed to parse foo object: " + foo, ex);
 }

Also, resist the temptation of emtpy catch blocks. They swallow the exception and you may never find out that something or what might be going wrong in your application. Log all exceptions unless you're very sure you'll never be interested in them.

0
votes

Create a custom error page, see here: How to show user-friendly error page in browser when runtime exception is thrown by servlet?

In the error page you can add some java code to log the exception with log4j.

Note: it is generally considered bad practice to put java code in a JSP, but logging in an error JSP is one place where I think it is acceptable.