Michael R. Head (suppressingfire) wrote,
Michael R. Head
suppressingfire

Getting the java.util.logging facilities to log messages of ALL levels...

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=ALL" in a logging.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.

Update (2010-12-10): Be a little more careful about loading the Logging.properties file. Throwing an exception from a static initializer will lead to a class load failure.
Tags: eclipse, java, programming
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments