Flushing streamhandlers during debugging using java.util.logging Autoflush
Asked Answered
P

1

7

I've been trying to look up this answer for a while on google and thought I'd just come here for the answer.

During production this setup works fine as it prints to both stdout and stderr which I separate and parse through for later use, but during development we want to see these logging actions be printed as they happen ie every log record. I think java refers to this as auto flushing. I cannot seem to find where I can change the buffer size for the stream handler objects that I have in order to fix this problem.

Some options I've though about are the following:

  1. Print the log to stdout in the Formatter
  2. Flush the handlers after every method call (Maybe with groovy annotations)
  3. Enable the console handler during debugging

I am using java.util.logging to handling all logging done with my application, we are creating a root logger using the following code:

public Logger buildLogger()
{
    Logger log = Logger.getLogger("") //TODO update when JDK updatesLogger.getGlobal() is what we would like to use here
    log.setLevel(Level.WARNING)
    log.setUseParentHandlers(false); //Turn off any Parent Handlers
    Handler[] handlers = log.getHandlers();
    for(Handler handler : handlers) {
        log.removeHandler(handler);
    }
    log.addHandler(soh); //Add stdOut Handler
    log.addHandler(seh); //Add stdErr Handler
    return log;
}

Handlers are here

public StreamHandler buildsoh()
    {
        def soh = new StreamHandler(System.out, formatter)
        soh.setLevel(Level.ALL); //Default StdOut Setting
        return soh;
    }

    public StreamHandler buildseh()
    {
        def seh = new StreamHandler(System.err, formatter)
        seh.setLevel(Level.SEVERE); //Default StdErr Setting
        return seh;
    }

Formatter is here:

public class MyLogFormatter extends Formatter {
    @Override
    public String format(LogRecord record) {
        StringBuffer log = new StringBuffer()
        log.append("[${record.getLevel()}]")
        log.append(new Date(record.getMillis()).format("yyyy-MM-dd HH:mm:ss"))
        log.append(" ")
        log.append("[").append(record.getSourceClassName() ?: record.getLoggerName())
        log.append(" ")
        log.append(record.getSourceMethodName() ?: " - ").append("]")
        log.append(": ");
        log.append(record.getMessage());
        log.append(System.getProperty("line.separator"));
        return log.toString();
    }
}

Thank you very much!

Parmer answered 7/1, 2015 at 17:59 Comment(1)
Maybe this will help? One fix would be to call soh.flush and seh.flush everytime I want the streamhandlers to flush their buffer. I just don't want to have to flush the handlers a bunch of times.Parmer
I
14

If you want to flush every record you log, may be this can be useful (in java):

public StreamHandler buildseh() {
    final StreamHandler seh = new StreamHandler(System.err, formatter) {
        @Override
        public synchronized void publish(final LogRecord record) {
            super.publish(record);
            flush();
        }
    };
    seh.setLevel(Level.SEVERE); // Default StdErr Setting
    return seh;
}
Isador answered 7/1, 2015 at 21:40 Comment(2)
You're the man, I'm going to make a few little adjustments but thats exactly right.Parmer
Thank you! This had been driving me insane. For whatever reason my StreamHandler was only calling write on the underlying OutputStream when it was closed, and even then only with the first character sent to it.Stricklin

© 2022 - 2024 — McMap. All rights reserved.