1

Trying to use java.util.logging and failing.

In an attempt to make use of https://stackoverflow.com/a/8249319/3322533 :

handlers = mypackage.logging.RequestFileHandler, mypackage.logging.MainFileHandler
config   =

mainLogger.handlers       = mypackage.logging.MainFileHandler

requestLogger.handlers    = mypackage.logging.RequestFileHandler

java.util.logging.ConsoleHandler.level     = INFO
java.util.logging.ConsoleHandler.filter    =
java.util.logging.ConsoleHandler.formatter = mypackage.logging.VerySimpleFormatter
java.util.logging.ConsoleHandler.encoding  =

mypackage.RequestFileHandler.level     = SEVERE
mypackage.RequestFileHandler.filter    =
mypackage.RequestFileHandler.formatter = mypackage.logging.VerySimpleFormatter
mypackage.RequestFileHandler.encoding  =
mypackage.RequestFileHandler.limit     =
mypackage.RequestFileHandler.count     =
mypackage.RequestFileHandler.append    = false
mypackage.RequestFileHandler.pattern   = REQUESTS.%u.%g.log

mypackage.MainFileHandler.level     = INFO
mypackage.MainFileHandler.filter    =
mypackage.MainFileHandler.formatter = mypackage.logging.VerySimpleFormatter
mypackage.MainFileHandler.encoding  =
mypackage.MainFileHandler.limit     =
mypackage.MainFileHandler.count     =
mypackage.MainFileHandler.append    = false
mypackage.MainFileHandler.pattern   = MAIN.%u.%g.log

where

public class MainFileHandler extends FileHandler {
    public MainFileHandler() throws IOException, SecurityException {
        super();
    }
}

and

public class RequestFileHandler extends FileHandler {
    public RequestFileHandler() throws IOException, SecurityException {
        super();
    }
}

Intention: provide two loggers accessible through

Logger.getLogger("mainLogger");

or

Logger.getLogger("requestLogger");

respectively, one that will write (exclusively) to MAIN[...].log and the other to REQUESTS[...].log

(No limits on the amount of messages that can be logged to either file and if necessary, use logging level to filter out unwanted msgs to either.)

However, neither file is created when I (for example)

public static final Logger log = Logger.getLogger("mainLogger");

and then

public void configureLogger(){
    try {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        InputStream config = classLoader.getResourceAsStream("logging.properties");

        LogManager.getLogManager().readConfiguration(config);

    }catch(Exception ex){
       throw new RuntimeException("logging properties failed");
    }
}

before I

log.info("Hello World!")

I know the properties are loaded because when I include java.util.logging.ConsoleHandler in the handlers = ... list and use the global logger, instead, the formatter is applied for the console output.

So ... I guess my attempt at setting up the file loggers is faulty. How do I get this working?

EDIT

So I removed the [...].pattern = [...] lines and instead hardcoded the file names:

public class MainFileHandler extends FileHandler implements FileHandlerProperties {
    public MainFileHandler() throws IOException, SecurityException {
        super("MAIN_" + new SimpleDateFormat(TIME_PATTERN).format(new Date()) + ".log");
    }
}

and

public class RequestFileHandler extends FileHandler implements FileHandlerProperties {
    public RequestFileHandler() throws IOException, SecurityException {
        super("REQUESTS_" + new SimpleDateFormat(TIME_PATTERN).format(new Date()) + ".log");
    }
}

where

public interface FileHandlerProperties {
    static final String TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
}

Both files now get created BUT they both contain exactly the same (despite their different level settings and loggers) AND what they contain is in xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2016-10-10T18:49:23</date>
  <millis>1476118163654</millis>
  <sequence>0</sequence>
  <logger>mainLogger</logger>
  <level>INFO</level>
  <class>mypackage.main.Main</class>
  <method>&lt;init&gt;</method>
  <thread>1</thread>
  <message>Hello World</message>
</record>
</log>

Please help ...

Community
  • 1
  • 1
User1291
  • 7,664
  • 8
  • 51
  • 108

1 Answers1

2

The problem is that the first call to Logger.getLogger during class loading reads the log configuration and your configureLogger method fails due to JDK-8033661: readConfiguration does not cleanly reinitialize the logging system.

To workaround this you have to ensure that configureLogger runs before the first call to Logger.getLogger.

public class BootMain {

    static {
        configureLogger();
        mainLogger = Logger.getLogger("mainLogger");
        requestLogger = Logger.getLogger("requestLogger");
    }

    private static final Logger mainLogger;

    private static final Logger requestLogger;

    public static void main(String[] args) throws IOException {
        mainLogger.log(Level.SEVERE, "Test from main.");
        requestLogger.log(Level.SEVERE, "Test from request.");
        System.out.println(new File(".").getCanonicalPath());
    }

    private static void configureLogger() {
        try {
            InputStream config = config();
            LogManager.getLogManager().readConfiguration(config);
        } catch (Exception ex) {
            throw new RuntimeException("logging properties failed");
        }
    }

    private static String prefix() {
        return "mypackage.logging";
    }

    private static InputStream config() throws IOException {
        String p = prefix();
        Properties props = new Properties();
        props.put("mainLogger.handlers", p + ".MainFileHandler");
        props.put("requestLogger.handlers", p + ".RequestFileHandler");
        props.put(p + ".RequestFileHandler.level", "SEVERE");
        props.put(p + ".MainFileHandler.level", "INFO");
        props.put(p + ".RequestFileHandler.pattern", "REQUESTS.%u.%g.log");
        props.put(p + ".MainFileHandler.pattern", "MAIN.%u.%g.log");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        props.store(out, "");
        return new ByteArrayInputStream(out.toByteArray());
    }
}

Also make sure you are not using a really old version of JDK or you can run into JDK-5089480: java.util.logging.FileHandler uses hardcoded classname when reading properties.

Otherwise you can use the LogManager config option to manually setup your configuration.

jmehrens
  • 10,580
  • 1
  • 38
  • 47