These days, I was asked about a strange network delay of input/output stream when migrating a TLS protected application to a new platform. The application is built on top of SunJSSE. They enabled debug with option “-Djavax.net.debug=all”, however, because there is no timestamp in the debug output, the debug logging was not of much help.

Is there any way to enable JSSE debug logging with timestamp? Definitely, the answer is YES. It is straightforward.

Firstly, create a class extends PrintStream,and override all println() methods. I used a static nested class here.

final static class TimestampPrintStream extends PrintStream {
    TimestampPrintStream(PrintStream out) {
       super(out);
    }

    public void println() {
       timestamp();
       super.println();
    }

    public void println(boolean x) {
       timestamp();
       super.println(x);
    }

    public void println(char x) {
       timestamp();
       super.println(x);
    }

    public void println(int x) {
       timestamp();
       super.println(x);
    }

    public void println(long x) {
       timestamp();
       super.println(x);
    }

    public void println(float x) {
       timestamp();
       super.println(x);
    }

    public void println(double x) {
       timestamp();
       super.println(x);
    }

    public void println(char x[]) {
       timestamp();
       super.println(x);
    }

    public void println(String x) {
       timestamp();
       super.println(x);
    }

    public void println(Object x) {
       timestamp();
       super.println(x);
    }

    private void timestamp() {
       super.print("<Thread Id: " +
          Thread.currentThread().getId() + ">" +
          "<Timestamp: " +
          System.currentTimeMillis() + ">    ");
    }
}

Surely, you can change the timestamp() to what kind of codes you like.

Then, insert into the following codes into a certain place, where the codes should be called before initialize a TLS connection, of your application. Simply, you can add it into the head of main() method.

if (true) {
	AccessController.doPrivileged(new PrivilegedAction<Void>() {
	    public Void run() {
	        System.setOut(new TimestampPrintStream(System.out));
            System.setErr(new TimestampPrintStream(System.err));
	        return null;
	    }
	});
}  

You see, it is simple and straightforward.