34

I have an application and need to code a custom global uncaught exception handler. I've read all the stackoverflow threads and each one of them is just missing a clear and simple example of how this is to be implemented.

Consider this simple following example:

public static void log(String msg) throws Exception {

    String logPath = "/application/logs/java.log";

    Calendar c = new GregorianCalendar();
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String now = format.format(c.getTime());

    PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logPath, true)));
    out.println(now + "  " + msg);
    out.close();

}

It throws a standard exception which is just a standard output. How do I implement my own exception which overrides the standard one by something simple as outputing the error into a log file? Obviously the actual application is much larger and we're talking about uncaught exceptions, which is why try/catch blocks is not the option.

UPDATE: If you could please answer with a very clear full example, because I found dozens of examples like the one @RamonBoza provided, yet I have no idea how to implement them, which is what this question is all about.

UPDATE2: So I've tried to test the only example in the answer below, it obviously doesn't work. I've created a new class file "MyRunnable" and pasted the code in it:

package mypackage;

Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

    public void uncaughtException(Thread t, Throwable e) {
       LOGGER.error(t + " throws exception: " + e);
    }
});
t.start();

//outside that class
class MyRunnable implements Runnable(){
    public void run(){
        throw new RuntimeException("hey you!");
    }
}

Needless to say I get a bunch of errors with this. How can something be outside of class anyway?

UPDATE3: This is the solution that finally works:

package mypackage;

public class MyClass {

    public static void main(String[] args) throws Exception {

        Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
            public void uncaughtException(Thread t, Throwable e) { 
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                String stacktrace = sw.toString();
                System.out.println(stacktrace);
            }
        });     

        //main method code

    }

    //Rest of the methods here

}
Caballero
  • 11,546
  • 22
  • 103
  • 163
  • Which exception does it throw? could you please provide the stack trace. – vallentin Oct 17 '13 at 09:10
  • @Vallentin this is just one method out of dozens on the application. This is not about one specific exception, I need to handle all possible uncaught exceptions. – Caballero Oct 17 '13 at 09:15
  • 1
    What is your higher-level goal here? What do you want to happen when there is an uncaught exception? Why do you want this? I suspect there may be a better way to do this. – Tom Anderson Oct 17 '13 at 09:33
  • @TomAnderson this question explains why I want this: http://stackoverflow.com/questions/19401904/java-error-log-output-ubuntu – Caballero Oct 17 '13 at 09:43
  • @Caballero: Aha. Normally, i would recommend that you don't try to trap uncaught exceptions in Java, but instead let the java process crash, and capture the output at the higher level. But it seems like that is precisely the problem you are trying to work around! – Tom Anderson Oct 17 '13 at 12:12
  • And to make it available to all threads, use the `ThreadGroup` of your thread, as answered here : http://stackoverflow.com/questions/33344294/java-uncaught-global-exception-handler-for-all-threads/33344392#33344392 – Benj Oct 26 '15 at 13:12

4 Answers4

33

You can set UncaughtExceptionHandler for the thread controlling the code above:

// t is the parent code thread
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

    public void uncaughtException(Thread t, Throwable e) {
       LOGGER.error(t + " throws exception: " + e);
    }
 });

Java docs for UncaughtExceptionHandler -

When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments

the setUncaughtExceptionHandler is commonly used to free memory or kill threads that the system will not be able to kill, and perhaps, remain zombie.

A real example:

Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

    public void uncaughtException(Thread t, Throwable e) {
       LOGGER.error(t + " throws exception: " + e);
    }
});
t.start();

//outside that class
class MyRunnable implements Runnable(){
    public void run(){
        throw new RuntimeException("hey you!");
    }
}
RamonBoza
  • 8,898
  • 6
  • 36
  • 48
  • 1
    How would I put this into my code? What exactly is "t" and how and where should I initialize it? – Caballero Oct 17 '13 at 09:17
  • is in the comment, t is the parent thread that have your code, btw you can use the setUncaughtExceptionHandler on your main Thread which will capture all the uncaught exceptions. As an example Thread t = new Thread(); t.setUncaughtExceptionHandler(...); – RamonBoza Oct 17 '13 at 09:20
  • 1
    Sorry for being blunt, but again - how do I use this and where exactly do I put it? I don't even use multithreading in my application so what is "the parent thread"? – Caballero Oct 17 '13 at 09:24
  • [`Thread.currentThread()`](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#currentThread%28%29) gets the object for the current thread. You could attach an `UncaughtExceptionHandler` to that. – Tom Anderson Oct 17 '13 at 09:31
  • This does not work. If I create a fresh class file "MyRunnable" and paste this code in - I get a bunch of errors... How can you have any code outside of class in a file anyway? – Caballero Oct 17 '13 at 09:31
  • All java application has, at least, one thread, so you will put it in your main thread, if you don't manually create any thread, use Thread.currentThread().setUncaughtExceptionHandler – RamonBoza Oct 17 '13 at 09:31
  • Sorry for that reply, but I dont undersand your comment `@Vallentin this is just one method out of dozens on the application. This is not about one specific exception, I need to handle all possible uncaught exceptions.` while you dont know how to create additional class files. – RamonBoza Oct 17 '13 at 09:37
  • In my real application I have a class with ~20 methods and `log` is just one of them. I didn't want to paste a few hundred lines here. – Caballero Oct 17 '13 at 09:40
  • into your main application, inside your public static void main, pase this `Thread.currentThread()..setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { LOGGER.error(t + " throws exception: " + e); } });` and change the `LOGGER.error` for your handling code – RamonBoza Oct 17 '13 at 09:42
5

You can use UncaughtExceptionHandler to handle the exception those causes a thread to terminate abruptly. Java doc for UncaughtExceptionHandler -

Interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception. When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments

You need to implement this interface and set your implementation of UncaughtExceptionHandler for a thread by using method setUncaughtExceptionHandler. There are two ways you can do this -

  1. setUncaughtExceptionHandler
  2. setDefaultUncaughtExceptionHandler

1) setUncaughtExceptionHandler - This will be a thread specific exception handler. So in case this thread gets terminated by some unhandled exception, this handler will be used.

2) setDefaultUncaughtExceptionHandler - This will be a default exception handler in case there is no specific uncaught exception handler for a thread.

Example -

class MyExceptionHandler implements UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread arg0, Throwable arg1) {
        System.out.println("[DEFAULT EXCEPTION HANDLER] Caught some exception");
    }
}

class MyThread extends Thread{
    public MyThread() {
        setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("[THREAD SPECIFIC] My exception handler");
            }
        });
    }
    public void run(){
        throw new RuntimeException();
    }
}

public class Test {

    public static void main(String[] args) {
        Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
        new MyThread().start();
        // current thread does not have a thread specific exception handler
        throw new RuntimeException();
    }

}
Sachin Gorade
  • 1,427
  • 12
  • 32
0

Main.java

import static org.app.DefaultUncaughtExceptionHandler.registerDefaultUncaughtExceptionHandler;

static {
    registerDefaultUncaughtExceptionHandler();
}

DefaultUncaughtExceptionHandler.java

import java.lang.Thread.UncaughtExceptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @see ThreadGroup#uncaughtException(Thread, Throwable)
 */
public class DefaultUncaughtExceptionHandler implements UncaughtExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(DefaultUncaughtExceptionHandler.class);
    private static final UncaughtExceptionHandler parent;
    private static final DefaultUncaughtExceptionHandler instance;

    static {
        parent = Thread.getDefaultUncaughtExceptionHandler();
        instance = new DefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(instance);
    }

    public static final void registerDefaultUncaughtExceptionHandler() {
        // registered
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (!(e instanceof ThreadDeath))
            logger.error("Exception in thread \"" + t.getName() + "\" ", e);
        if (parent != null)
            parent.uncaughtException(t, e);
    }
}
Mike
  • 20,010
  • 25
  • 97
  • 140
-1

You can try setting your own uncaught Exception handler, however I strongly advise against it. If your application has parts that can potentially break and if that exception is then not properly handled at the location where your code breaks, your entire program will malfunction frequently.

TwoThe
  • 13,879
  • 6
  • 30
  • 54
  • 11
    The whole point of exceptions is *NOT* having to handle exceptions at the location they are raised, but in an higher layer that knows better. – gpeche Oct 17 '13 at 09:33