ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Build Flexible Logs With log4j

by Vikram Goyal

log4j is the open source logging tool developed under the Jakarta Apache project. It is a set of APIs that allows developers to write log statements in their code and configure them externally, using properties files. This article explains the main concepts of this tool, followed by some advanced concepts using a Web-based example application.

A Note on the Accompanying Application

The application that accompanies this article is a Web-based application, which has been developed and tested using JDK1.3.1, Tomcat 4.0.1, log4j 1.2.4 and Ant 1.4.1 on a Windows XP machine. You can download the log4jdemo.war application file that you can deploy in any servlet engine. You can also download the source code. This application has the following flows, which are found in most Web applications:

  • Main Page --> Login --> Welcome Page --> Submit Comments.
  • Main Page --> Register --> Login.
  • Main Page --> Forgot Password.

Keep in mind that the application itself is trivial and is just a path to the main goal in this article -- understanding log4j. I have opted for a Web application to explain log4j instead of a normal application because of the high number of Web applications using log4j as the preferred logging mechanism.


log4j can be downloaded from the Apache Web site. The download is available in two formats, tar.gz and zip. Both downloads contain the source code for the log4j API, documentation, examples, and distributable log4j executables in the form of .jar files. Extract the files to a location of your choice. The source code is supplied, in case you want to do a build for yourself. The build can be done with the help of Ant and the build.xml files that are provided; you can customize the build script if required. The build will produce the log4j-1.2.4.jar file in the dist/lib directory if built using the dist target. Note that for the build to be successful, you will need to have the Java Management Extensions (JMX) API in your classpath, as well.

To make the log4j classes available to your application, you need to have the log4j-1.2.4.jar file in the classpath of your application. This file, as described above, is in the dist/lib folder. For our example Web application, this means that this .jar file should be in the WEB-INF/lib directory of our application. This is all that is required to make sure that your application can access and use the log4j API. The rest of the effort needs to go into writing a configuration file that tells log4j what, where, and how to log, and into introducing actual log statements in your application.

What Is a Logger?

Before we start cutting some code, let's look at the basics of log4j. There are three aspects of log4j: logger, appender, and layout. A logger logs to an appender in a particular layout (style).

Related Reading

Java In a Nutshell
By David Flanagan

Think of a logger as the silent component within your application that will take your request for logging and log it. Each class in your application can have an individual logger or a common logger. log4j provides a root logger that all of your loggers will inherit from. This also means that if you don't have an individual logger for each class, you can always use the root logger by calling Logger.getRootLogger(), although this is not recommended.

To create a logger and use it for logging in your classes, you typically need to call a static method of the Logger class that will retrieve a logger for you by name. If the particular logger has not already been created it will be created for you, and there will always be one instance of this logger in your JVM.

Loggers need to know where to send your requests for logging. This is where the appenders come into picture. log4j supports writing to files (FileAppender), to console (ConsoleAppender), to databases (JDBCAppender), to NT event logs (NTEventLogAppender), to SMTP servers (SMTPAppender), to remote servers (SocketAppender), and others. An appender defines the properties of the logging target to log4j. So, for example, if we attach a JDBCAppender to one of our loggers, we are telling log4j that logging requests from our logger should go to a certain database (using a certain username, password, connection string, etc.). All of these are properties of an appender (a JDBCAppender in this case), which are used by log4j to target our logging requests.

Loggers and appenders are concerned with originating and targeting our log requests. What about the format of the output? This is where a layout comes into picture. A layout defines the style and content of the output log. Some built-in layouts are provided with log4j, and you can create your own layouts, if they are required. A layout will tell log4j whether or not to include the date and time in the output, whether to include information about the logger, whether to include the line number from which the log originated, etc.

Loggers follow a parent-child relationship pattern. As mentioned earlier, log4j provides a root logger by default. This implies that all of our loggers will ultimately inherit from this root logger. A parent-child relationship is followed by using a named pattern. To illustrate, let's say you have a class called MyClass in a package called com.foo.bar. In this class, let's instantiate a logger by the name of com.foo.bar.MyClass. In this case, com.foo.bar.MyClass logger will be a child of the logger com.foo.bar -- if it exists. If it does not exist, the only ancestor of the com.foo.bar.MyClass logger will be the root logger provided by log4j (in case there is no logger by the name of com.foo or com).

Each logger in log4j is assigned a level. If you don't assign a level to a logger yourself, log4j automatically assigns to your logger the level of the parent logger. Since there is a possibility that the user might not assign any level to the self-created logger(s), the root logger always has a default level assigned to it, which is DEBUG. Thus, all loggers are guaranteed to have a level.

There are five levels of logging in log4j:

  • INFO
  • WARN

The signs indicate the ordering of the logging that log4j follows.

How does each logger having a level affect our logging efforts? Because a log request made from within our application using a particular logger will be sent to a corresponding appender only if the level of the log request is greater than or equal to the level of the logger itself. This means that all log requests from within our application can be of these five types only. This is a very important rule, and really is at the core of log4j. Let's take our previous example of com.foo.bar.MyClass logger to explain this further.

Suppose within your class (which is called com.foo.bar.MyClass -- no surprise here; we named our logger based on the class where it is instantiated, a standard practice), you use the logger to log a message of type WARN. Now let's say your logger com.foo.bar.MyClass has the level set at ERROR through your configuration. What does this mean? This means that the log request of type WARN will not be sent to any appender.

Why? Because log4j recognizes that the level of the log request is lower than the level of the logger, and thus does not log this request. Had the log request been of type ERROR or FATAL, it would have been logged. Similarly, had the level of the logger been set at level WARN, the log request would have been logged. This leads to a very important concept about log4j. You can externally change the level of each and every logger without having to change your source code, recompile, and deploy.

log4j is mostly configured using an external configuration file. The API provides for configuring the log4j system through code as well. The next section will guide you through a simple example and show how the configuration can be done.

Pages: 1, 2, 3

Next Pagearrow