Tuesday, August 25, 2009

Using Log4J from a WebSphere Based Application

Log4J is an easy to use and powerful logging system. This article will show you how to best configure and use Log4J from a typical WebSphere based application.

We will develop a J2EE 1.3 application and test it with WebSphere V5.

Initializing Log4J

Initializing Log4J has been a thorny problem for a J2EE application. There are two ways to initialize Log4J:

  1. Call PropertyConfigurator.configure(String propertyFileName) - This function takes the full path name of the properies file that contains Log4J configuration information. A J2EE application should not make any assumption about where its files are located in the file system. Use of this function requires the application to know exactly that.
  2. Do not call PropertyConfigurator.configure() and let Log4J look for a properties file called log4j.properties in a J2EE module's class path. The lookup takes place when the Logger.getLogger() method is called for the first time. In this article we recommend using this approach.

A Typical log4j.properties File

#Default log level to ERROR. Other levels are INFO and DEBUG.
log4j.rootLogger=ERROR, ROOT
log4j.appender.ROOT=org.apache.log4j.RollingFileAppender
log4j.appender.ROOT.File=myapplication.log
log4j.appender.ROOT.MaxFileSize=1000KB
#Keep 5 old files around.
log4j.appender.ROOT.MaxBackupIndex=5
log4j.appender.ROOT.layout=org.apache.log4j.PatternLayout
#Format almost same as WebSphere's common log format.
log4j.appender.ROOT.layout.ConversionPattern=[%d] %t %c %-5p - %m%n

#Optionally override log level of individual packages or classes
log4j.logger.com.webage.ejbs=INFO

This configuration file exploits the following features of Log4J:

  1. Set the global log level. ERROR will print messages logged with the Logger.error() method. INFO will print messages logged with Logger.error() and Logger.info(). Finally, DEBUG will print all messages including the ones logged with the Logger.debug() call.
  2. Rotate log files. In this example, when the log file (myapplication.log) reaches 1000KB, it is closed, backed up and a new log file is created.
  3. Set the log format to display timestamp, class name and the message.
  4. Optionally override the global log level for individual Java packages or classes. In this example we set the log level for the com.webage.ejbs package to INFO.

Using Log4J From a Web Module

In this section we will learn how to install and use Log4J from an application built entirely as a Web module (that is, does not use EJBs).

Start WSAD and create a J2EE 1.3 Enterprise Application Project called LogTest and a Web module within it called LogTestWeb. Create a file called log4j.properties in the Java Source folder of the Web module. Add configuration entries similar to as shown in the section above. When you build the web project, the properties file will be automatically copied into the WEB-INF/classes folder. Do not directly create the properties file in the WEB-INF/classes folder. WSAD will delete it, next time the web project is re-built.

Download the latest Log4J distribution. Extract the JAR file from the distribution (for example log4j-1.2.8.jar) and copy it to the Web Content/WEB-INF/lib folder of the Web module.

Add a Java class to the Web module called com.webage.model.MyModel. Add a method called checkValid(String name, String value) as follows:

package com.webage.model;

import org.apache.log4j.Logger;

public class MyModel {
static Logger logger = Logger.getLogger(MyModel.class);;

public void checkValid(String name, String value) throws Exception {

logger.debug("ENTRY");
logger.debug("Checking parameter: " + name);
if (value == null) {
throw new Exception("Parameter is absent.");
}
if (value.trim().length() == 0) {
throw new Exception("Parameter is empty.");
}

logger.debug("EXIT");
}
}
Advanced
In real life, model Java classes are often created in a separate Java Project. In that case, add the Log4J JAR file located within the Web module to the build path of the Java project. This will let you compile the Java classes. At run time classes from the Java project will be loaded by the Web module's class loader which will also load the Log4J classes from the WEB-INF/lib/log4j-1.2.8.jar JAR file. If you wish to run the Java classes stand alone (from JUnit for example), you will need to configure the class path of the launch configuration to add the Log4J JAR file as well as the WEB-INF/classes folder.

Add a Servlet with the class name com.webage.servlets.MyServlet. Set the contents of the Servlet's class as follows:

package com.webage.servlets;

import java.io.IOException;
import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.webage.model.MyModel;

public class MyServlet extends HttpServlet {
Logger logger = Logger.getLogger(MyServlet.class);

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
logger.debug("ENTRY");

MyModel model = new MyModel();

resp.getWriter().println("

Log4J Test Servlet

");
try {
model.checkValid("firstName", req.getParameter("firstName"));
} catch (Exception e) {
logger.error("doGet failed.", e);
}

logger.debug("EXIT");
}

public void init() throws ServletException {
super.init();
logger.info("Servlet initializing...");
}
}

Test

Associate the LogTest project with a WebSphere V5 Server. Run the Servlet. By default, the firstName parameter is absent and the MyModel.checkValid method will throw an exception. The servlet will log the exception. The global log level is set to ERROR and Log4J will add the log entry to the log file. The log file (myapplication.log) will be created in the WSAD installation root directory.

Open log4j.properties and enable DEBUG level log for the com.webage.model package by adding the line:

log4j.logger.com.webage.model=DEBUG

Restart the LogTest project for the change to take effect. Run the Servlet again and check the content of the log file. DEBUG level log from the MyModel class will be shown.

Troubleshooting

If you do not see the log file (myapplication.log) in the root installation directory of WSAD, chances are Log4J did not initialize properly. If Log4J fails to locate the log4j.properties file in the class path, it will put a message in the standard output as shown below.

[3/14/03 13:04:05:498 EST] 19daf47c SystemErr R log4j:WARN No appenders could be found for logger (com.webage.servlets.MyServlet).
[3/14/03 13:04:05:498 EST] 19daf47c SystemErr R log4j:WARN Please initialize the log4j system properly.

In UNIX systems, make sure that spelling of the properties file is correct (log4j.properties in all lower case).

In all systems use the UNIX style forward slahes in the log file name. For example:

log4j.appender.ROOT.File=c:/temp/myapplication.log

Using Log4J in a EJB Application

Create a new EJB module called LogTestEJB under the LogTest Enterprise Application module. Move the Log4J JAR file from the WEB-INF/lib folder of the LogTestWeb module to the root directory of the LogTest project. Create a folder called lib under the LogTest project and move the log4j.properties file there.

Build a Java JAR dependency from the LogTestEJB project to the Log4J JAR file (right click on LogTestEJB and select Properties. Select Java JAR Dependency and check the Log4J JAR file).

Similarly, build a Java JAR dependency from the LogTestWeb project to the log4J JAR file and the LogTestEJB.jar file.

Add the LogTest/lib directory to the class path of the server. To do this, switch to the Server perspective and double click on your server in the Server Configuration view. Click on the Paths tab. Next to the Class Path list click on Add Folder. Select LogTest/lib.

Test

Add a simple Session EJB called MySession in the LogTestEJB project. Add logging to the bean class MySessionBean.java as follows:

import org.apache.log4j.Logger;

public class MySessionBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
Logger logger = Logger.getLogger(MySessionBean.class);
//...
public void aMethod() {
logger.debug("ENTRY aMethod");
logger.debug("EXIT aMethod");
}
}

Promote aMethod() to the remote interface and use the EJB from the Servlet. Finally,test the Servlet.

Deploying in WebSphere

Export your application from WSAD as a EAR file. Install the EAR in WebSphere. This will, by default, extract the contents of the EAR in /installedApps/ folder. Copy the log4j.properties file from this folder to the /properties folder. This folder is automatically added to the class path of every application server.

By default, the directory is setup as the working directory of an application server. To create the Log4J log file in the standard /logs directory, open log4j.properties and change the log file name as follows.

log4j.appender.ROOT.File=logs/extranet.log

Conclusion

In this article we explore how to use Log4J from an exclusively web based application as well as a EJB and web based application. Our goal was to simplify the process of development and administration. We achieve this in several ways.

  1. We do not develop any additional code to deal with Log4J initialization.
  2. We make the Log4J JAR file a part of the J2EE application. There is no need to distribute and install this JAR file separate from the application's EAR file.
  3. In case of a pure web based application, there is no additional administration involved. The application will be able find log4j.properties from the WEB-INF/classes folder. For an application that has EJB modules, one will need to configure the application server's classpath to point to the directory where log4j.properties is stored.