Add logging to your Java applications

Don't reinvent the wheel when adding event logging to your Java apps. Follow these examples, and in no time at all, you can be using the Log4j package to capture your application events.

Every application needs a way to gather and communicate data to the outside world. This can be through an interface, with a database, or by using text files. With so many options available, the use of a common text file for data collection or debugging seems to have been forgotten. But although text files don’t offer that tingle you get from the latest cool technology, they are effective for collecting data and diagnosing problems with applications.

The Log4j package
The libraries available in the Java programming language make it easy to write data to files, but why reinvent the wheel when a good package is already available? The Java 2 SDK version 1.4 will have a logging API built into the language, but until it is a little more mature, I would prefer to stick with something a bit more proven—like the Log4j package. I've found it to be robust, dependable, easy to expand, and simple to implement. You can get Log4j from the Apache Jakarta project. To use the package, you just need to have the log4j.jar file somewhere in the CLASSPATH for your application.

Categories start at the root
The Log4j package is organized around the concept of categories. Log4j can have any number of categories at any time during the running of your application. There will always be a root category, which is the start of the hierarchy of categories. Categories are named using a dot notation just like Java packages. This makes it easy to place specific logging within your application using the existing structure of your code to control how logging statements are handled.

Categories inherit, so a category named com.versatilesolutions.example would inherit settings from the com.versatilesolutions category. You can apply priorities to a category to control the amount of logging your application performs. The available priorities are debug, info, warn, error, and fatal. When you call the logging routine, you specify the priority of your log statement by using methods that correspond to the different priorities. If the operation you are performing is expensive, you can check whether the current priority is active so that the expensive operation is only performed if the statement will actually be logged.

Type of logging and layout
Log4j uses appenders to specify what type of logging is performed when a statement is received by the logging package. Log4j's standard appenders are screen, file, rotating file, and a remote appender that allows the collection of log data in a central location. The appenders are applied to the categories so that different parts of the application can have different log destinations.

Once you have set the priority and appenders for the categories, the only requirement left is to specify a layout. Layouts control the exact format of your logging statements, such as the date, time, module name, and thread identifications. I won’t try to cover all the available formats since you can get an excellent summary of these from the Log4j documentation.

Configuring Log4j can be done with an XML file or a Java properties file. I prefer the Java property file technique since it is really overkill to use an XML file for this purpose. Listing A contains a property file used to configure Log4j.

The first noncomment line in this property file specifies that the root category has a priority of debug and has three appenders, identified by A1, A2, and A3. The remaining sections specify the appender for each identifier. In this property, the appenders are a console (screen), a rotating file, and a UDP broadcaster.

The UDP broadcaster is an appender I added to the Log4j package so that I can watch log statements interactively. Each appender has a layout object attached. In this case, the PatternLayout is used and the conversion pattern follows. The characters in the conversion pattern specify the output. The % sign is used to specify a format character. In this example, %-5p stands for left alignment using five characters for the priority (p). Next is the date (%d), the thread information (%t), and the message (%m), followed by a line termination character (%n).

To use Log4j in your application, you need to load this property file by using a PropertyConfigurator. A line like this in your startup class should do the trick:
import org.apache.log4j.PropertyConfigurator;

Once the configuration is loaded, each class within your application that requires logging capability needs a reference to the category object. Since the category uses a package naming convention, I often use the class name as the category even though this is not required, depending on how you have arranged the configuration. Declaring a single static variable for the class will make the logging routines available:
import org.apache.log4j.Category;
private static final Category log = Category.getInstance(MyClass.class.getName());

Logging the event
Now logging within your application is easy. Just call the method that corresponds to the priority of the message you are logging. For instance, here's a debug message:
log.debug("Log4j really works!");

If you wanted to make sure the debug priority was active, you could check it before making the debug call. Note that the message would not be logged even if you sent it, unless the priority was set properly. Checking the current priority is simply a method to avoid expensive operations prior to attempting the log operation. Here is an example of checking the priority before the log statement.
if ( log.isDebugEnabled() ) {
   log.debug("Another log statement.”);

You can also add an exception to the log method so that the details of the exception are included with the log message. This call takes the following form:
log.warn("Oops caught an exception.", myException);

This should be all you need
If your current application or future development requires a robust logging facility, take a look at the Log4j package. It offers a great deal of flexibility, and with a configurable appender and priority system, you can control the logging and adjust it for your release product without significant overhead in the system.

Tracking your app
Do you have a preferred way to track application events? How have you implemented an event-logging system? Send us an e-mail with your thoughts and suggestions or post a comment below.


Editor's Picks