Rob
Rob

Reputation: 718

configure Logger via global config file

I'd like to have 1 configuration file that contains information about how/where/what logger in particular class should log.

Example:

class Foo

package myApp;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

class Foo {
    static final Logger logger = Logger.getLogger(Foo.class.getName());

    public static void main(String[] args) throws IOException {

        FileInputStream fis =  new FileInputStream("C:\\path\\to\\myApp.log.properties");
        LogManager.getLogManager(). readConfiguration(fis);

        logger.log(Level.INFO, "Msg message");

        Bar obj = new Bar();

        obj.doSth();
}

class Bar

package myApp;

import java.util.logging.Level;
import java.util.logging.Logger;

public class Bar {

    static final Logger logger = Logger.getLogger(Bar.class.getName());

    public Bar() {
    }

    public void doSth() {
        logger.log(Level.WARNING, "Msg message");
    }
}

File myApp.log.properties

handlers = 
config   =

myApp.Foo.handlers           = java.util.logging.ConsoleHandler
myApp.Foo.useParentHandlers  = false
myApp.Foo.level              = INFO

myApp.Bar.handlers           = java.util.logging.ConsoleHandler
myApp.Bar.useParentHandlers  = false
myApp.Bar.level              = INFO

Output:

Jul 23, 2014 1:27:12 PM myApp.Bar doSth
WARNING: Msg message

As you can see, the log record for Foo is missing, i guess it's because logger is static and is created before configuration for LogManager is loaded and set.

Could you please suggest solution where log record is printed for Foo's logger? Also with a static logger and without using commandline parameter -D configFile when the program is executed?

Upvotes: 0

Views: 1779

Answers (1)

jmehrens
jmehrens

Reputation: 11065

In your example, LogingToFile.doSth is called instead of Bar.doSth. Modify your config file to include:

myApp.LogingToFile.handlers           = java.util.logging.ConsoleHandler
myApp.LogingToFile.useParentHandlers  = false
myApp.LogingToFile.level              = INFO

Or add new Bar().doSth(); to your main method.

Reading through the LogManager source code it appears that Handlers are only loaded when the logger is created after the configuration is set. This is bug JDK-8033661 readConfiguration does not cleanly reinitialize the logging system. The listed workarounds are:

  • Do not use per-logger handlers in your log configuration file
  • Do not call readConfiguration() or readConfiguration(InputStream), but store the configuration in a file and load it on JVM startup
  • Configure your logging through API calls

Given your constraints, the workaround will be to load the configuration before creating the loggers.

class Foo {

    static {
        try (FileInputStream fis = new FileInputStream("C:\\path\\to\\myApp.log.properties")) {
            LogManager.getLogManager().readConfiguration(fis);
        } catch (IOException ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    static final Logger logger = Logger.getLogger(Foo.class.getName());

    public static void main(String[] args) throws IOException {
        logger.log(Level.INFO, "Msg message");

        Bar obj = new Bar();

        obj.doSth();
    }
}

Upvotes: 1

Related Questions