0

I'm trying to use JUL logger with a customized configuration, so that special handlers take care for different logging levels. I want severe problems (such as failures when connecting to database or reading the properties) logged into a local file, warnings should be written into the database by my custom handler, everything else is supposed to be a debugging output and should be printed to console if debugging is enabled. So here are my logger properties:

logger.level = SEVERE
logger.handlers = java.util.logging.FileHandler

logger.warning.level = WARNING
logger.warning.handlers = controller.database.DatabaseHandler

logger.warning.severe.level = ALL
logger.warning.severe.handlers = java.util.logging.ConsoleHandler

java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.append = false
java.util.logging.FileHandler.pattern = %h/app.log

controller.database.DatabaseHandler.level = WARNING

java.util.logging.ConsoleHandler.filter = controller.properties.DebugFilter
java.util.logging.ConsoleHandler.level = ALL

Until now the database handler doesn't do anything but a sysout for testing:

@Override
public void publish(LogRecord arg0) {
    System.out.println("DatabaseHandler here! - Level="  + arg0.getLevel() + " - From=" + arg0.getLoggerName());

}

And finally here is my test code:

LogManager.getLogManager().readConfiguration(new FileInputStream("logProps.properties"));
Logger logger = Logger.getLogger("logger.warning.severe");
logger.log(Level.FINE, "A fine message", new Object());
logger.log(Level.WARNING, "A warning message", new Object());
logger.log(Level.SEVERE, "A severe message", new Object());

What i would expect is that the first message gets printed out to the console, passsed to "logger.warning" and then discarded, as it's below the logging level. The same for the second message in "logger", so the only one printed to the file is the third message. However the console output looks like this:

DatabaseHandler here! - Level=FINE - From=logger.warning.severe
03.07.2015 07:54:55 controller.LoggerTest main
FEIN: A fine message
03.07.2015 07:54:55 controller.LoggerTest main
WARNUNG: A warning message
DatabaseHandler here! - Level=WARNING - From=logger.warning.severe
03.07.2015 07:54:55 controller.LoggerTest main
SCHWERWIEGEND: A severe message
DatabaseHandler here! - Level=SEVERE - From=logger.warning.severe

Also all three messages get printed to the file. I've ran out of ideas to explain this behaviour, can anybody help please?

P.S. log4j is NOT an option, otherwise I would have used it

Regards, Sverre

SverreN
  • 177
  • 1
  • 9
  • Maybe this SO answer might be of help. http://stackoverflow.com/questions/8248899/java-logging-how-to-redirect-output-to-a-custom-log-file-for-a-logger#8249319 – SubOptimal Jul 03 '15 at 07:16

1 Answers1

1

What i would expect is that the first message gets printed out to the console, passsed to "logger.warning" and then discarded, as it's below the logging level.

From the Java Logging Overview:

By default a Logger will log any output messages to its parent's handlers, and so on recursively up the tree.

When log records travel up the tree they are not passed to logger.log. Therefore, the level of the parent logger has no effect when the child logger is publishing to the parent handlers.

I want severe problems (such as failures when connecting to database or reading the properties) logged into a local file, warnings should be written into the database by my custom handler, everything else is supposed to be a debugging output and should be printed to console if debugging is enabled.

First should set the level of FileHandler to SEVERE, set the DB handler to WARNING, and the ConsoleHandler to all. Then you have to install a custom filter on the ConsoleHandler and DB handler to block out the levels that are handled elsewhere:

    public class LessThanLevelFilter implements Filter {

        private final int lvl;

        public LessThanLevelFilter() {
            String p = getClass().getName();
            String v = LogManager.getLogManager().getProperty(p + ".level");
            if (v != null) {
                lvl = Level.parse(v).intValue();
            } else {
                lvl = Level.WARNING.intValue();
            }
        }

        public LessThanLevelFilter(Level l) {
            lvl = l.intValue();
        }

        @Override
        public boolean isLoggable(LogRecord record) {
            return record.getLevel().intValue() < lvl;
        }
    }
jmehrens
  • 10,580
  • 1
  • 38
  • 47
  • Additional to this answer the Database handler must perform it's own isLoggable() test before doing anything else. Else this answer works perfectly, thanks! – SverreN Jul 07 '15 at 12:57