Ultimate Java Logging

Several logging systems exist for Java. There is the Java logging built-in to the latest libraries, which doesn't allow very flexible configuration and doesn't even allow source code line-numbers in the log. There is also the tried-and-true Apache Log4j package, which offers great flexibility but isn't built-in to Java. These two systems have a lot in common, and oftentimes a project is forced to choose one or the other based mostly on the personal preferences of the team members. Once a project commits to a particular logging framework, it's not so easy to switch, as logging is pervasive in the code. Furthermore, logging framework choice is global, even if the framework chosen has flexible configuration. I've created a new logging framework that provides a simple, generalized interface that can be configured to delegate to your favorite logging system, or to rely on its own easy-to-use default implementation.

I had already created a unique and flexible configuration framework, and logging seemed like a good test case to show how the framework can be used. So I created a new logging framework that can be configured to use either of the main logging frameworks (or its own default logging implementation), transparent to the code doing the logging. The framework is extremely easy to use and configure, and it can even be configured to use different implementations in different parts of the program.

Here's how easy it is to log a warning using the new GlobalMentor logging framework in the com.globalmentor.log package:

Log.warn("Be careful!");

That's all the code needs to do. If no further configuration has been done, the default implementation will send non-errors to System.out and errors to System.err.

But what if you want to log errors to a file? Just install a new default log configuration before logging starts:

Log.setDefaultConfiguration(new File("application.log"));

Java Logging

The GlobalMentor logging default implementation has various configuration options, but you probably would rather  use the logging package you're already used to. Here's how you would configure the system to use the built-in Java logging.

Log.setDefaultConfiguration(new JavaLoggingLogConfiguration());

Yep, that's it. The same logging line above, Log.warn("Be careful!"), would now log a warning using the Java logger for the class of the caller. (The GlobalMentor logging system automatically senses which class is doing the logging so that you don't have to worry about it.) By default Java logging sends log messages to System.out, but you can configure Java logging globally as you normally would.

Log4j Logging

You might be used to Log4j. You can configure it to be used with the GlobalMentor logging framework as such:

BasicConfigurator.configure();
Log.setDefaultConfiguration(new Log4jLogConfiguration());

Note that an extra line is needed. This is only because Log4j does not provide a default configuration, as the Java logging system does. Instead of a basic configuration, you can configure Log4j as you normally would. Lines such as Log.warn("Be careful!") will automatically go to the correct Log4j logger.

More Options

You may be worried that the GlobalMentor logging framework uses too much overhead when it divines the calling class. You can pass the calling class in manually, if you like, for even more speed:

Log.warn(MyClass.class, "Be careful!");

And if you want even more efficiency by keeping a logger around for the class as you might do with the Java logging system or Log4j, you can do that, too:

Logger logger=Log.getLogger(MyCLass.class);
logger.warn("Be careful!");

This approach reduces the overhead of the GlobalMentor logging classes to almost zero.

Note that the logging methods accept varargs, so you can report an error like this, for example:

Log.error("The file ", myFile, " could not be loaded.", ioException);

The GlobalMentor logging system will automatically concatenate the provided objects, and if one of them is a Throwable, it will be passed as such to those logging implementations (e.g. Log4j) that accept it.

The configuration framework allows different configurations for different parts of your application. Guise™, for example, uses this capability to provide different log configurations for each Guise application running on the same JVM. If that's not enough, you can even configure one part of your program to use Log4j and another to use Java logging! The actual logging invocation never changes. You can reconfigure your program at any time to use another logging implementation by changing a single line of code.

The GlobalMentor logging system can be found in com.globalmentor.jar in the com.globalmentor.log package. The source code is available from the GlobalMentor com.globalmentor.log Subversion repository or as an archive in com.globalmentor.src.zip.