tags:

views:

1303

answers:

8

How can I detect when an Exception has been thrown anywhere in my application?

I'm try to auto-magically send myself an email whenever an exception is thrown anywhere in my Java Desktop Application. I figure this way I can be more proactive.

I know I could just explicitly log and notify myself whenever an exception occurs, but I'd have to do it everywhere and I might(more likely will) miss a couple.

Any suggestions?

A: 

In this case I think your best bet might be to write a custom classloader to handle all classloading in your application, and whenever an exception class is requested you return a class that wraps the requested exception class. This wrapper calls through to the wrapped exception but also logs the exception event.

toluju
+3  A: 

The new debugging hooks in Java 1.5 let you do this. It enables e.g. "break on any exception" in debuggers.

Here's the specific Javadoc you need.

Jason Cohen
+4  A: 

Check out Thread.UncaughtExceptionHandler. You can set it per thread or a default one for the entire VM.

This would at least help you catch the ones you miss.

Justin Rudd
A: 

If you're using a web framework such as Spring then you can delegate in your web.xml to a page and then use the controller to send the email. For example:

In web.xml:

<error-page>
  <error-code>500</error-code>
  <location>/error/500.htm</location>
</error-page>

Then define /error/500.htm as a controller. You can access the exception from the parameter javax.servlet.error.exception:

Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");

If you're just running a regular Java program, then I would imagine you're stuck with public static void main(String[] args) { try { ... } catch (Exception e) {} }

Mat Mannion
That example applies to any "WebApp" and has nothing to do with Spring or web frameworks. It also only applies to uncaught exceptions which bubble up to the base servlet class, thus causing the http status 500 -- which may (or may not) be what is wanted.
Cheekysoft
Ah, thanks - I only have experience with Spring so I didn't want to speak out of turn :)
Mat Mannion
A: 

I assume you don't mean any Exception but rather any uncaught Exception.

If this is the case this article on the Sun Website has some ideas. You need to wrap your top level method in a try-catch block and also do some extra work to handle other Threads.

Dave Webb
+14  A: 

You probobly don't want to mail on any exception. There are lots of code in the JDK that actaully depend on exceptions to work normally. What I presume you are more inerested in are uncaught exceptions. If you are catching the exceptions you should handle notifications there.

In a dektop app there are two places to worry about this, in the Event Dispatch Thread (EDT) and outside of the EDT. Globaly you can register a class implementing java.util.Thread.UncaughtExceptionHandler and register it via java.util.Thread.setDefaultUncaughtExceptionHandler. This will get called if an exception winds down to the bottom of the stack and the thread hasn't had a handler set on the current thread instance on the thread or the ThreadGroup.

The EDT has a different hook for handling exceptions. A system property 'sun.awt.exception.handler' needs to be registerd with the Fully Qualified Class Name of a class with a zero argument constructor. This class needs an instance method handle(Throwable) that does your work. The return type doesn't matter, and since a new instance is created every time, don't count on keeping state.

So if you don't care what thread the exception occured in a sample may look like this:

class ExceptionHandler implements Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
    handle(e);
  }

  public void handle(Throwable throwable) {
    try {
      // insert your e-mail code here
    } catch (Throwable t) {
      // don't let the exception get thrown out, will cause infinite looping!
    }
  }

  public static void registerExceptionHandler() {
    Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
    System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
  }
}

Add this class into some random package, and then call the registerExceptionHandler method and you should be ready to go.

shemnon
Nice! Thanks for the code.
Allain Lalonde
Why do you need last line System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName()); It's working without this line. And sun.awt could be specific to sun's implementation I guess.
feiroox
In case the Exception is thrown in side the Event Dispatch Thread. The Swing/AWT EDT has their own Exception catcher at the root of their thread and this is the hook into it.
shemnon
Are you sure about the infinite looping part? The documentation of UncaughtExceptionHandler.uncaughtException(...) states: Any exception thrown by this method will be ignored by the Java Virtual Machine. (see: file:///usr/lib/jvm/java-6-sun/docs/api/java/lang/Thread.UncaughtExceptionHandler.html)
jilles de wit
Who reads javadocs? So it won't cause infinite looping, but this makes it wholly expressive in the code. And prior to 1.5 you need to do this in the ThreadGroup, which made no such promises. So the code and thinking is legacy.
shemnon
A: 

Sending an email may not be possible if you are getting a runtime exception like OutOfMemoryError or StackOverflow. Most likely you will have to spawn another process and catch any exceptions thrown by it (with the various techniques mentioned above).

Nik
It's worth noting the difference between Errors and Exceptions. Both are Throwable, but Errors aren't Exceptions as they are siblings.
Cheekysoft
A: 

If you are using java 1.3/1.4, Thread.UncaughtExceptionHandler is not available. In this case you can use a solution based on AOP to trigger some code when an exception is thrown. Spring and/or aspectJ might be helpful.

Alexandre Victoor