logo

Logging for All

The Case for Logging

A very valid point is often raised to during development of any server application: it is hard to know what a given subsystem is doing. In fact, it is often hard to know what the system as a whole is doing.

There are some facilities available (e.g. it is usually possible to know the SQL statements executed), but globally it is very difficult to know what's going on, and when possible it is nearly always module-specific. Very often there is no way to activate tracing for everything.

Almost all projects have a need for a global logging facility. Instead of peppering System.err.println() right and left, how about deploying some sort of global logger object that can be used for all debugging/tracing/maintenance purposes? And it would be great help for profiling too.

Log4j, a Jakarta project, is a fantastically useful tool that belongs in every Java developer's toolbox. The goal of this article is to introduce you to Log4j, its features, and how to deploy it in your own code.

What are the Features of Log4j?

  • log4j is optimized for speed.
  • log4j is based on a named category hierarchy. Logging behavior can be set at runtime using a configuration file. Configuration files can be property files or in XML format.
  • log4j is designed to handle Java exceptions from the start.
  • log4j can direct its output to a file, the console, a java.io.OutputStream, java.io.Writer, a remote server using TCP, a remote Unix syslog daemon, to a remote listener using JMS, to the NT event log or even send e-mail.
  • log4j uses 5 priority levels, namely DEBUG, INFO, WARN, ERROR and FATAL. The format of the log output can be easily changed by extending the Layout class.
  • the target of the log output as well as the writing strategy can be altered by implementations of the Appender interface.

How to Log with Log4j

In order to shield your code base from a change in logging packages (something that can always happen, especially considering the close advent of a Sun-blessed logging facility), I recommend you encapsulate log4j in your own com.mycompany.logging.Logger class. The Logger class implements the Facade design pattern. All logging actions should be done through that class. Doing otherwise would introduce extra dependencies we want to avoid at all cost. The source code for that class is available for download.

And now for a code sample:

import com.mycompany.logging.Logger;

class MyLoggingClass
{
   private static final Logger LOG = Logger.newInstance( MyLoggingClass.class );

   void myLoggingMethod()
   {
      log.debug("this is a debugging message");
      log.info("this is an informational message");
      log.warn("this is a warning!");
      log.error("this is an error!!");
      log.fatal("this is a fatal error!!!");
   }
}

All logging methods are also available with a Throwable parameter:

debug(String, Throwable)
info(String, Throwable)
warn(String, Throwable)
error(String, Throwable)
fatal(String, Throwable)

Each has an associated priority, in increasing order:

debug < info < warn < error < fatal
The log can filtered according to priority and category. E.g. in the log4j configuration file (text or XML) I can say "only log stuff coming from com.waldura.system at priority >= WARN". The log format can be fully customized, right now I make it look like this:
date time PRIO package.class method:line - message
Last but not least you can decide where the logged data is sent, e.g. by email, to a file, etc. The default log configuration logs everything from every class to the console.

Conclusion

Log4j is cool, and you'll love it. Get rid of those lame System.out.println() as I did, and you'll have a killer tool to track those bugs down.

References


Copyright © 2000-2007 Renaud Waldura <renaud@waldura.com>