Search code examples
javalog4jstderrprintstream

Add time to an exception displayed with STDERR


In my application, I use log4j. all the logs are written in a file, but if an error STDERR not handled by my logs occurs, it is redirected in an other file. For example, the non-handled NullPointerException appear in this other file.

I need to add the date/time before the exception. I use a custom PrintStream for that :

Main.java

public class Main {
    MyPrintStream ps;

    public static void main(String[] args) {
        System.setErr(new MyPrintStream(System.out));
        Integer i = null;
        String str = i.toString();
    }
}

MyPrintStream.java

public class MyPrintStream extends PrintStream {
    public MyPrintStream(OutputStream out) {
        super(out);
    }

    @Override
    public void println(String string) {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        super.println(simpleDateFormat.format(date) + " " + string);
    }
}

Output:

Exception in thread "main" java.lang.NullPointerException
2018-03-21 18:05:53.749     at test.Main.main(Main.java:9)

What I need:

2018-03-21 18:05:53.749 Exception in thread "main" java.lang.NullPointerException
 at test.Main.main(Main.java:9)

In my output, there is a date for each line. I tried to override the print method, and there is 3 times the date. How to display the date only once, at the beginning of the exception ?

I have an other possible solution, it is to display a log with log4j each time this kind of non-handled exception occur, but I don't know how to do if the exception is not catched...


Solution

  • I found a solution. I could do an log4j appender to redirect stderr, and my files would be the sames.

    I can use the UncaughtExceptionHandler to add the date on the non-catched errors:

    public static void main(String[] args) {
    
    
            Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    Date date = new Date(); // faire le new Date() ici, en dehors du block, garanti d'avoir une heure au plus juste, mais les traces pourraient être au final dans le désordre dans le fichier
                    synchronized (System.err) {
                       System.err.print(simpleDateFormat.format(date) );
                               System.err.print(" Exception in thread \""+t.getName()+"\" "); 
                       e.printStackTrace(System.err);
                    }
                 }
            });
    
            Integer i = null;
            String str = i.toString();
    
        }
    

    I can redirect System.err to a file if I want.