Commons-logging in WebSphere Application Server 6.0
WebSphere Application Server 6.o uses commons-logging and is loaded by the application server's class loader. Normally logging would configured on the server level through the administration console. Go to Troubleshooting, click Logging and Tracing > server name > Change Log Detail Levels and configure what needs to be logged there. However, there are times when the WebSphere logging is not enough and applications need something more powerful such as Log4j to do the logging. It is recommended that the class loaders are left to the default policies rather than switching to PARENT_LAST or using an APPLICATION rather than MODULE policy. This will ensure you are coding to spec and make it easier for you to switch application servers if needed (e.g. Geronimo on the development workstations and WebSphere Application Server for the production servers). It also prevents leaks when restarting applications as the class loader and all its data are unloaded cleanly. To configure Log4j to work on an application deployed in WebSphere 6.0, the application module must have the commons-logging.jar and log4j.jar file within its classpath. It is then a matter of invoking the LogFactory.setAttribute() method on initialization. For web modules, create an initialization servlet as follows:
public class InitServlet extends GenericServlet implements Servlet {
public void init() {
LogFactory.getFactory().setAttribute(
LogFactoryImpl.LOG_PROPERTY,
Log4JLogger.class.getName());
DOMConfigurator.configure(
getClass().getClassLoader().getResource("log4jconfig.xml"));
}
public void service(ServletRequest request, ServletResponse response) {
}
public void destroy() {
LogFactory.releaseAll();
}
}Some notes:
- The DOMConfigurator line specifies where to find the Log4J configuration to use.
- The destroy() method is used to release all the Log objects that were created by the LogFactory within the current class loader in order to prevent leaks when restarting.
- A log statement may be put into the service() method, to indicate successful configuration of the LogFactory.
public abstract class BaseSessionBean implements SessionBean {
public void ejbCreate() throws CreateException {
LogFactory.getFactory().setAttribute(
LogFactoryImpl.LOG_PROPERTY,
Log4JLogger.class.getName());
DOMConfigurator.configure(
getClass().getClassLoader().getResource("log4jconfig.xml"));
}
public void ejbRemove() {
LogFactory.releaseAll();
}
}This is similar to the InitServlet except that it uses the EJB constructs rather than that of Servlets. This base class has to be extended by all EJBs in the project to ensure that the LogFactory gets configured correctly. However, this is very intrusive to the application since it introduces the Fragile Base Class antipattern.
To solve the antipattern, two things need to be done: create a custom LogFactory and let the module know to use the custom LogFactory. The custom log factory looks like this:
public class CustomLogFactory extends LogFactoryImpl {
private static final String LOGGER = Log4JLogger.class.getName();
protected String getLogClassName() {
setAttribute(LOG_PROPERTY, LOGGER);
return super.getLogClassName();
}
protected Constructor getLogConstructor() throws LogConfigurationException {
setAttribute(LOG_PROPERTY, LOGGER);
return super.getLogConstructor();
}
}Some notes:
- The getLogClassName() and getLogConstructor() methods are called by LogFactory in order to create the actual log.
- The setAttribute() method for the two methods in order to ensure that the Log wanted is the Log4J logger. Putting the setAttribute() in the constructor does not work.

4 comments:
Can you explain the purpose of using this InitServlet? I made it work without using InitServlet. Of Course, it is true that it is doing releaseAll. You know, by default, commons-logging will detect log4j. And it will detect log4j.properties too, if it is in the application classpath.
Were the class loader policies left as the defaults? If they are then you'd need the InitServlet to load up the proper configuration file that is set up in the EAR rather than the one that comes with WebSphere.
The classloader policies left as default
Hi A.T.,
I try to use log4j with WAS 6.1 and I have a problem. I use Struts and then I create a private instance of Logger for each Action class I have.
I use a log4j.properties file placed in the classes directory. And I have log4j.jar placed in application lib's directory.
The application logs all on my laptop (Windows - WAS 6.1.0.9) but doesn't produce logs on the server (Linux - WAS 6.1.0.9).
Could you help me ?
Thanks
Post a Comment