15.3 Jakarta Commons Logging

The Commons Logging package is an open source Logging library that allows developers to use a common logging API, while maintaining the freedom to use many different third-party logging implementations. The Commons Logging API insulates the application and protects it from becoming coupled to a specific logging implementation. The API provides a small set of Java classes and interfaces that an application imports and relies upon but that has no implicit dependencies on any one logging product.

The Logging library allows developers to declaratively configure the logging implementation; the library will dynamically discover which implementation is being used. An application that uses the Commons Logging API does not have to be modified when the logging implementation is changed. This is the greatest benefit of such a package.

The Commons Logging package supports several logging implementations out of the box:

·         log4j (http://jakarta.apache.org/log4j)

·         JDK 1.4 Logging

·         LogKit (http://jakarta.apache.org/avalon/logkit)

·         SimpleLog (writes log messages to stdout and stderr)

·         NoOpLog (log messages are ignored)

The Commons Logging package includes only the SimpleLog and NoOpLog implementations; it does not contain the other third-party logging implementations. You will need to download those separately.

Another powerful feature of the Commons Logging package is that it is completely extensible. If you are using a logging package that is not yet supported, you can create an adapter to that implementation by extending the appropriate components, and your application can use the Commons Logging API.

15.3.1 Installing the Commons Logging Package

You can download the latest source and binary code for the Commons Logging package at http://jakarta.apache.org/commons/logging.html. Struts 1.1 already includes commons-logging.jar, which is the only required binary file. Unless you want the absolute latest from the nightly build, the version included with the Struts framework should suit your needs. You should place the commons-logging.jar file into the WEB-INF/lib directory for the web application.

You will also need to decide on a logging implementation. The Commons Logging package includes an implementation called SimpleLog that writes log messages to stdout and stderr. If you don't want to worry about getting log4j working and are not using Java 1.4, the SimpleLog implementation is a good choice to get things started.

Once you decide on an implementation, you must configure the implementation class so that the Commons Logging factory component can discover it at application startup. There are many ways to do this, but the easiest is to create a properties file called commons-logging.properties that contains the class name of the logging implementation. The most important property key in this file is the org.apache.commons.logging.Log key, which is used to set the implementation class.

The following illustrates how to set up the Commons Logging package to use the SimpleLog implementation:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

At runtime, the logging component will search for the commons-logging.properties file and attempt to instantiate the fully qualified class name found there. The class name specified must be available to the web application class loader. The properties file should be placed in the WEB-INF/classesdirectory. To switch to log4j, all you need to do is switch the class name in the commons-logging.properties file, like this:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog

Note that you still need to configure log4j for your environment, including creating a log4j.properties file. Each logging implementation may have different configuration requirements that must be satisfied.

15.3.2 Using the Commons Logging API

Once the configuration steps are completed, your application is ready to use the Commons Logging API. You must include the following import statements in each class or component in which you wish to use the logging API:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

To get an instance of a log component to which you can send log messages, you need to use either of the getLog( ) factory methods on the org.apache.commons.logging.LogFactory class:

public static Log getLog(Class class);
public static Log getLog(String name)

Both getLog( ) methods return an object that implements the org.apache.commons.logging.Log interface. To create a Log instance to be used within the LoginAction class, for example, you could pass the class name to the getLog( ) method:

Log log = LogFactory.getLog( LoginAction.class );

The Log instance would then be available for use within the LoginAction class:

if (log.isInfoEnabled(  )){
  // Log which user is trying to enter the site
  log.info( "Login email: " + email );
}

The Log interface implements the logging methods that you can use to send log messages to the intended destination. The most important of these are:

·         debug( )

·         error( )

·         fatal( )

·         info( )

·         trace( )

·         warn( )

Each of these log methods has an overloaded version that takes a Throwable. There are also methods that allow you to determine whether debug is enabled, whether error is enabled, and so on. Checking to see if a particular logging level is enabled before attempting to log a message can improve the performance of your application. For example, if you have this code fragment:

StringBuffer buf = new StringBuffer(  );
buf.append( "Login Successful - " );
buf.append( "Name: " );
buf.append( userView.getFirstName(  ) );
buf.append( " " );
buf.append( userView.getLastName(  ) );
buf.append( " - " );
buf.append( "Email: " );
buf.append( userView.getEmailAddress(  ) );
 
// Log the information for auditing purposes
log.debug( buf.toString(  ) );

it would improve the performance of the application if the append statements were not all executed when the logging threshold was set to not log debug statements. You can use the isDebugEnabled( ) method for this:

if ( log.isDebugEnabled(  ) ){
  StringBuffer buf = new StringBuffer(  );
  buf.append( "Login Successful - " );
  buf.append( "Name: " );
  buf.append( userView.getFirstName(  ) );
  buf.append( " " );
  buf.append( userView.getLastName(  ) );
  buf.append( " - " );
  buf.append( "Email: " );
  buf.append( userView.getEmailAddress(  ) );
 
  // Log the UserView for auditing purposes
  log.debug( buf.toString(  ) );
}

In this case, the application is not wasting time creating the StringBuffer only to have it not be used.

15.3.3 Struts Framework and the Commons Logging Package

The Struts framework does perform some limited internal logging, and also uses the Commons Logging API. Thus, the Struts framework will use whichever logging implementation you configure for your application.

The Struts logs are a great way for you to see what's going on inside Struts as it processes requests, but other than for debugging purposes, there's no need for you to worry about them. In most production environments, the messages generated by the Struts framework should be disabled. The manner in which you disable the framework-specific log messages depends on which logging implementation you choose.

The rest of this chapter is devoted to one of the most popular logging implementations used by developers, log4j. Because it's also supported by the Commons Logging package, it's an excellent choice for your Struts application's logging needs.