Creating Log Output

Another major item that administrators want control of is logging. Logging is the process of generating output when something occurs. That something could be an error, warning, or message. It's important to generate log output because it tells the administrator what the application is doing, and it saves the administrator from having to resort to using a debugger. Administrators are sophisticated computer people, but they are not programmers in the sense we use the term in this book. The closest the administrator wants to get to programming is setting the verbose flag on the application (more on this shortly).

Here are the basic logging levels:

  • error : Something caused an error in the application, and that causes the application to generate the reason why an error occurred.

  • warning : Something is causing a problem, but the application can cope with the problem. An example includes having two aliases pointing to the same item. This condition is not an error but should not occur.

  • informational : Something of importance has occurred and the application makes a note of it. An example includes identifying the database connection that the server is using. An informational-type log output is extremely important because it allows an administrator to troubleshoot and see where things are going wrong.

  • verbose : Whatever has occurred while the program is running, including errors, warnings, messages, etc., are output. This type of log output should be used only when you're debugging very complicated problems. A verbose log output is very similar to a debug output, in that everything that could be important is logged. When the verbose mode is activated, logging can and will impair the performance of the application. It is not meant to be a general logging mode.

The Logging package in the Commons project is not an entire package; rather, it's a wrapper for other logging packages. The Logging package provides a wrapper for the Java logging mechanism, Avalon Framework, and the Log4J package.

Technical Details for the Logging Package

Tables 8.7 and 8.8 contain the abbreviated details necessary to use the Logging package.

Table 8.7: Repository details for Logging package



CVS repository


Directory within repository


Main packages used

org.apache.commons.logging (contains the core logging classes); org.apache.commons.logging.impl (contains the implementations of the interface Log; more details are given in the Java Docs and later in this chapter)

Table 8.8: Package and class details (legend: [logging] = org.apache.commons.logging).




A core interface used to generate log messages

A Simple Log Example

Logging an error can be really simple, as shown in Listing 8.30.

Listing 8.30
start example
 Log log = new SimpleLog( "myLogFile"); log.error( "some error"); 
end example

In Listing 8.30, the interface Log is the core interface used to access the logging implementation. There are multiple implementations of the interface Log , which are all located in the package org.apache.commons.logging.impl . In Listing 8.30, the implementation SimpleLog is used. Then, to log a message, the method error is called. What the method error does is up to the implementation of the Log interface. In Listing 8.30, the error is output to the System.err stream.

The following are the available Log interface implementations:

  • AvalonLogger : A class that accepts as a constructor parameter an Avalon Logger interface instance. The Log interface wraps the Avalon Logger interface instance, and whenever errors occur, the Avalon Logger handles them.

  • Jdk14Logger : A class that wraps the standard JDK logging mechanisms introduced in the JDK 1.4.

  • Log4JLogger : A class that maps the Log interface methods to the Log4J logger. Using the Log4J logger requires that the Log4J library be properly configured.

  • LogKitLogger : A class that maps the Log interface to the Avalon Logging system. The Avalon Logging system needs to be properly configured.

  • NoOpLog : A class that implements the Log interface but does nothing with it.

  • SimpleLog : A class that implements the Log interface and outputs all of the log messages to the System.err stream.

Defining the Logging Levels

In Listing 8.30, the error that was logged would have been output. However, in the default level, any warning or debug message will be ignored. This means that debug messages will be ignored when only error messages are to be logged. For example, Listing 8.31 is an example of how you can use the logging interface in a production coding setting.

Listing 8.31
start example
 Log log = getLogImpl(); try { log.debug( "Allocating the bean"); BeanToWrite bean = null; bean.setIntegerValue( 1234); "Carried out logic"); } catch( Exception ex) { log.error( "oops message", ex); } 
end example

In Listing 8.31, three levels are used. The method info is used to create an informational message. In Listing 8.31, the important event is that the bean logic has been carried out. The method debug is used to create a verbose log output. In Listing 8.31, the verbose log output is the allocation of a specific bean. It is important to realize the difference between log outputs. For informational-type log outputs, the objective is to log logic, or business- related , actions. For verbose-type log outputs, the objective is to log resource or programmatic actions, like an allocation.

Finally, when an error occurs, it is logged using the method error. Unlike the other logging methods, error has two parameters. The first parameter represents the error message. The second parameter represents an exception that has been thrown. The underlying logging implementation will then log the exception to give better details on what caused the error.

The Log interface has more methods than logging levels defined in the beginning of this Logging section. Here are the individual logging levels methods listed, cross-referenced with the associate level:

  • fatal : This method is an error level that defines a fatal error, meaning that the program can no longer continue and must exit.

  • error : This method is an error level that needs to be logged. However, you could let the program continue, albeit not optimally.

  • warn : This method is a warning level that needs to be logged. The program can recover and still functional correctly. However, certain parts of the program may not be operational.

  • info : This method is an informational level. The program will output business- or logic-related information, such as database server started, or mortgage completed.

  • debug : This method is a verbose level. The program will output programmatically related issues, such as memory allocation or network connections.

  • trace : This method is a verbose level. The method is used to output almost every detail of the program, without using a debugger. Using this method should slow down the entire program because of the number of logging calls made.

Activating the Logging Process

Using the Logging package is not that difficult; in fact, it can be relatively simple. However, we haven't yet explored what is going on underneath the package. In Listing 8.31, the method getLogImpl was a custom method that instantiates an instance of the Log interface implementations. (Of course, since you've been reading this chapter, you know that this method would be based on a configuration item.) Regardless of which implementation you use, you need to configure the underlying logging implementation properly. If the implementation is related to Log4J, the Avalon logging toolkit, or JDK logging, you can get further information from the associated logging implementation.

If the implementation of the method getLogImpl uses the SimpleLog class, supplied by the Logging package, a configuration file has to be provided. The configuration file defines how to generate the log output. When the SimpleLog class is instantiated , the file is searched for. Typically, this file should reside in the classpath or a jar file. Listing 8.32 is a sample file.

Listing 8.32
start example
 org.apache.commons.logging.simplelog.defaultlog=debug org.apache.commons.logging.simplelog.log.myLogFile=debug org.apache.commons.logging.simplelog.showlogname=true org.apache.commons.logging.simplelog.showShortLogname=true org.apache.commons.logging.simplelog.showdatetime=true 
end example

If you want to understand this configuration file, it is simpler to remove the package prefix and consider Listing 8.33. (Note that in an actual configuration file, the package prefix is required.)

Listing 8.33
start example
 defaultlog=debug log.myLogFile=debug showlogname=true showShortLogname=true showdatetime=true 
end example

When the class SimpleLog is instantiated, the property that defines the debug level is searched for. In Listing 8.33, this means the properties defaultLog and log.myLogFile . There are two properties because the property defaultLog is the default logging level. The identifier log.myLogFile is a specific logging level identifier. The identifier myLogFile is the same identifier passed to the constructor of the class SimpleLog that was demonstrated in Listing 8.30. The available levels are: all , trace , debug , info , warn , error , fatal , and off . The level all indicates that all logging outputs should be activated. The level off indicates that nothing should be logged. The levels of logging ordered into levels of priority are fatal , error , warn , info , debug , and trace , where fatal is first and highest priority. For example, if the level fatal is defined, then only fatal errors will be output because fatal is the first and highest priority. The lowest and last priority is the level trace , which is like the level all and logs all outputs.

In Listing 8.33, the remaining properties are defined as follows :

  • showlogname : The default is false; if this is set to true , it outputs the specific logging identifier.

  • showShortLogname : The default is true and outputs a short form of the specific logging identifier. This is important only if the logging identifier is separated by dots to indicate a namespace-type definition.

  • showdatetime : The default is false; if this is set to true , it is used to output the current time and date.

Checking If a Level Is Available

In Listing 8.32, the individual method levels were called without regard to whether or not the debug level was enabled. The problem with doing that is evident in Listing 8.34.

Listing 8.34
start example
 Log log = getLogImpl(); try { "Allocating the bean"); BeanToWrite bean = null; bean.setIntegerValue( 1234); log.debug( "Carried out logic" + bean.isValidObject()); } catch( Exception ex) { log.error( "oops message", ex); } 
end example

In Listing 8.34, look at the method debug. The output string is a concatenation of a string and the output of the method isValidObject . The problem with this form of debug logging output is that the text might be ignored. And, if the text is ignored, that would mean that the method call isValidObject would be unproductive. A more productive way of writing Listing 8.34 is Listing 8.35.

Listing 8.35
start example
 Log log = getLogImpl(); try { "Allocating the bean"); BeanToWrite bean = null; bean.setIntegerValue( 1234); if( log.isDebugEnabled()) { log.debug( "Carried out logic" + bean.isValidObject()); } } catch( Exception ex) { log.error( "oops message", ex); } 
end example

In Listing 8.35, the method call debug has been encapsulated within a decision block. The decision block calls the method isDebugEnabled to query if the debug level is output. The method isDebugEnabled exists for all levels using the pattern is[mode]Enabled .

When you're writing complicated logging code, enabled method calls are preferred. Enabled method calls like those shown in Listing 8.35 are preferred because they will not affect resource- intensive or time-critical code that may or may not output an informational message. If the enabled code did not exist, the message would be output, even if the debugger will not do anything with the message. Consider it as follows: a simple process would be to send mail to somebody whenever something occurs. But if the person does not want such a level of detail, then sending the mail will cost money and time. Hence, it is better to ask the person if he wants to be informed.

Applied Software Engineering Using Apache Jakarta Commons
Applied Software Engineering Using Apache Jakarta Commons (Charles River Media Computer Engineering)
ISBN: 1584502460
EAN: 2147483647
Year: 2002
Pages: 109 © 2008-2017.
If you may any questions please contact us: