I spent some time today trying to figure out how to get my FINE
, FINER
, and FINEST
log messages to print to the console without having to programmatically configure the Logger
objects and without having to tweak the command line. Essentially, I wanted to configure the levels using a call to LogManager.readConfiguration(...)
at the start of my program's execution.
My key misunderstanding was failing to realize that it is necessary to configure the level on both the handler and the package level. That is, it's not enough simply to set ".level=ALL" or "java.util.logging.ConsoleHandler.level=Alogging.properties
file. They must both be set in order to get the handler to both match and print all messages. This issue can also show up when using the Apache Commons Logging library without log4j
under Java 1.4 or higher.
Here are the two code snippets I've taken to using (depending on if I want to depend on a Logging.properties file in my project or if I just want to configure the logger inline).
String config = "handlers = java.util.logging.ConsoleHandler" + "\n" + ".level = ALL"+"\n"+"java.util.logging.ConsoleHandler.level = ALL"; InputStream ins = new ByteArrayInputStream(config.getBytes()); Logger logger = Logger.getLogger(Main.class.getName()); try { LogManager.getLogManager().readConfiguration(ins); } catch (IOException e) { logger.log(Level.WARNING, "Failed to configure log manager due to an IO problem", e); } logger.fine("Logger initialized");
And here's the equivalent code if a Logging.properties is nearby in the classpath:
static Logger logger = Logger.getLogger(TestDriver.class.getName()); static { try { String name = "Logging.properties"; InputStream is = TestDriver.class.getResourceAsStream(name); if (is == null) { is = TestDriver.class.getResourceAsStream("/" + name); } if (is == null) { logger.log(Level.WARNING, "Failed to configure log manager. " + name + " was not loadable as a resource. It should be in the same directory as " + TestDriver.class.getSimpleName() + ".class"); } else { LogManager.getLogManager().readConfiguration(is); } } catch (SecurityException e) { logger.log(Level.WARNING, "Failed to configure log manager due to an access problem", e); } catch (IOException e) { logger.log(Level.WARNING, "Failed to configure log manager due to an IO problem", e); } catch(Exception e) { logger.log(Level.WARNING, "Failed to configure log manager due to an unknown problem", e); } }
And in the same directory as the Constants.class
file, there should be a Logging.properties
like so:
handlers= java.util.logging.ConsoleHandler .level= ALL java.util.logging.ConsoleHandler.level = ALL
A word of caution: It is questionable whether it is a good idea to force this setting in code. For example, in large systems, it is preferable to have a single console for setting all logging levels across all handlers and classes in a way that won't be overwritten by code such as what I've posted above. On this point, I agree strongly, so this should only be used at the "edge" of the system (for example, in a command line program that is meant to be run at the console, perhaps as the main-class in a jar). So this code is probably best placed at the top of the main()
method.