Using ConsoleHandler with own PrintStream suppress

2019-09-01 09:19发布

问题:

I want the Java ConsoleHandler to use System.out instead of err, so I implemented my own handler that calls the protected void setOutputStream(OutputStream) of the parent StreamHandler class:

public class ConsoleHandler extends java.util.logging.ConsoleHandler {

    public ConsoleHandler() {

        setOutputStream(System.out); // or System.err
        setLevel(Level.ALL);
    }
}

I remove the default console logger from and add my own to the root logger:

Logger l = Logger.getLogger("");
for (Handler h : l.getHandlers())
    l.removeHandler(h);
l.addHandler(new ConsoleHandler());

System.out.println("OUT");
System.err.println("ERR");

Problem: "OUT" is always printed, but "ERR" never, independent of the output stream I set in my ConsoleHandler constructor.

回答1:

The stacktrace (printed to System.err) is not printed any more, without my changes it is printed as usual

This is because setOutputStream closes the previously assigned System.err stream. This is a known issue filed under JDK-4827381: Invoking ConsoleHandler.setOutputStream(...) closes System.err. What should have happened with that bug report is that the StreamHandler.setOutputStream should call Handler.close instead of flushAndClose().

You need to wrap the existing System.err stream with a proxy that doesn't allow the stream to be closed. Or just extend StreamHandler and use the constructor that takes an OutputStream.

public class OutConsoleHandler extends StreamHandler {

   public OutConsoleHandler() {
        super(System.out, new SimpleFormatter());
        //TODO: Read level,filter,encoding from LogManager.
   }

    @Override
    public void publish(LogRecord record) {
        super.publish(record);
        super.flush();
    }

    @Override
    public void close() {
        super.flush();
    }
}