David’s Choice for Java Error Logging
October 4, 2002 Timothy Prickett Morgan
Hey, David:
Thanks for all the tips you have given us. You have saved us countless hours of frustration. In return, here is a tip for you.
|
Where I work, we were trying to decide how to log errors and other diagnostic messages from our Java applications.
With all the choices (i.e., LogKit, Log4J, JDK14), we were not sure what was best.
We knew we needed something, but did not want to lock ourselves into a logging framework that would not meet our needs.
That was when we found that the Jakarta-Apache project (http://jakarta.apache.org) had a project that was perfect.
The Commons-Logging project (http://jakarta.apache.org/commons/logging.html) provides a common interface to several of the logging packages available (including all of the ones mentioned above) as well as a simple API that you can use to add your own implementations.
This means we are free to try any of these implementations without concern for how our applications will use them. The interface to LogKit is exactly the same as the interface to the JDK14 logger or Log4J.
There is even a SimpleLog implementation that comes with it. To use it, all we did was set an environment variable using the -D switch when starting our JVM. (If you are using Tomcat, you can add this to your TOMCAT_OPTS or CATALINA_OPTS environment variable.)
java -Dorg.apache.commons.logging.Log=org.apache. commons.logging.impl.SimpleLog
Now, in our application code, we use the LogFactory class to get an object that implements a simple Log interface. Here is a simple example:
package example; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public static void main(String arg[]){ Log myLog = LogFactory.getLog("myLogName"); myLog.info("Here is an informational message."); }
The LogFactory either creates a new log, or returns an existing one if you have previously requested one with the same name (in this example “myLogName”).
What makes this so compelling is that now our applications are completely independent of our logging implementation. All they see is the commons-logging interface.
For now, the SimpleLog is enough. But if we decide to switch to LogKit, or even write our own to send a pager message when a fatal message is logged, all we do is reconfigure the LogFactory, and all of our application code remains unchanged.
Also, any other tools that use the commons-logging mechanism for logging (like Tomcat or struts) use our preferred logging scheme as well.
There is one caveat: The creators of the commons-logging project intentionally left configuration of the underlying logging implementation out of their code. This means if you want to use a new logging implementation, you have to figure out how to configure it yourself as you would have even without the commons-logging project.
The trade off is that now you are free to experiment with other implementations and see what is available without ever changing even one line of your application code.
Log on!
— Larry
Thanks for sharing the tip, Larry. Following your lead, I went ahead and wrote a logger that sends logging messages to the joblog when running on an iSeries system. These two classes make it easier to use the Commons logging framework on the iSeries. To get started, download the Log and AS400Logger classes as well as the Commons Logging package . Install these on your iSeries system and compile them with an optimization level of 40.
On my system, I set my logging level to debug or trace while developing or maintaining programs. In production, I set the logging level to warn. The supported levels in order are trace, debug, info, warn, error, and fatal. Here is a sample of code that does selected logging:
try { if (rs == null) { if (Log.isDebugEnabled()) { Log.debug("Empty result set passed to: " + ResultsetToCollection.class.getPackage() + ".ResultsetToCollection.convert(ResultSet, Collection)"); } } else { rows = (Collection) clazz.newInstance(); Object column = null; while (rs.next()) { column = rs.getObject(1); rows.add(column); } } } catch (Exception e) { Log.warn("Exception occurred in: " + ResultsetToCollection.class.getPackage() + ".ResultsetToCollection.convert(ResultSet, Collection)"); throw e; }
The commons logging interfaces define several levels of logging that need to be supported. Code messages are logged under certain conditions if the logging level is debug or warn. You can check to see if a logging level is enabled before actually sending a message. This helps avoid the overhead associated with creating the parameters passed to the logging methods. The test for Log.isDebugEnabled() near the top of this code is an example of this.
Using a common interface for logging certainly makes sense. Your code will be more consistent and portable.
— David
Sponsored By COMMON |
Get the IT Training You Need By Attending COMMON Users Group’s Fall 2002 IT Education Conference & Expo October 13-17 in Denver, Colorado Choose from over 720 sessions and labs covering the widest range of industry topics. Also receive training from J.D. Edwards and MAPICS. Registration is $1,395–the best value in midrange education. Don’t miss out! Click www.common.org |