[ Team LiB ] Previous Section Next Section

Recipe 14.7 Logging Messages Using a Servlet Context Event Listener

Problem

You want to log messages using log4j when a servlet context is created and shut down.

Solution

Use log4j and a servlet context event listener.

Discussion

The servlet API includes a listener interface named javax.servlet. ServletContextListener that you can use to notify a specific Java class when a servlet context is created or shut down. This notified class may want to log the servlet context creation or shut down or store an object attribute in the servlet context, actions that the Java class (the listener) takes when it receives its notification.

The servlet context listener is an application event listener, a category that also includes session event listeners (see Chapter 11 or Recipe 14.8) and request event listeners. For example, the session event listener receives notifications when the servlet container creates new HTTP session objects in order to track a user's progress through a web application. The servlet container notifies the request event listener when a user makes a web application request, so that a listener can take some kind of action—such as logging the user's IP address.

A javax.servlet.ServletContext is used to store attributes or access context parameters that are common to a web application, get RequestDispatcher objects for forwarding or including files (see Chapter 6), or get information such as an absolute pathname associated with a web resource. Every web application has one associated servlet context.

There is one servlet context instance per web application (per Java Virtual Machine (JVM), in the case of distributed web applications) according to the ServletContext Javadoc: http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContext.html.


log4j is a good choice for generating custom-designed log messages from a class that implements the ServletContextListener interface. Example 14-12 shows the ContextLogger class, which uses log4j to send messages in its two methods.

Example 14-12. A servlet context event listener that sends log messages
package com.jspservletcookbook;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import javax.servlet.*;
import javax.servlet.http.*;

public class ContextLogger implements ServletContextListener {


  private Logger log;

  public ContextLogger( ){}
  
  public void contextDestroyed(ServletContextEvent sce)  {
  
    String name = sce.getServletContext( ).getServletContextName( );
    
    //log request of the INFO level
    log.info("ServletContext shut down: " + (name == null ? "" : name ));

    //do other necessary work, like clean up any left-over resources
    //used by the web app  
  } 
    
  public void contextInitialized(ServletContextEvent sce) {

    ServletContext context = sce.getServletContext( );

    String realPath = context.getRealPath("/");
    String fileSep = System.getProperty("file.separator");

    //Make sure the real path ends with a file separator character ('/')
    if (realPath != null && (! realPath.endsWith(fileSep))){
          realPath = realPath + fileSep;}


    //Initialize logger here; the log4j properties filename is specified
    //by a context parameter named "logger-config"

    PropertyConfigurator.configure(realPath +
     "WEB-INF/classes/" + context.getInitParameter("logger-config"));

    log = Logger.getLogger(ContextLogger.class);

    String name = context.getServletContextName( );

    //log request about servlet context being initialized
    log.info("ServletContext ready: " + (name == null ? "" : name ));
      
  }
}

Give this class a no-args constructor, place it in WEB-INF/classes or in a JAR located in WEB-INF/lib, and register it in web.xml:

<listener>
    <listener-class>
    com.jspservletcookbook.ContextLogger
    </listener-class>
</listener>

The ServletContextListener tracks the lifecycle of a servlet context with two methods: contextInitialized( ) and contextDestroyed( ). The servlet container calls the first method when the servlet context is created and the web application is ready to receive its first request. The container notifies the listener class and calls the contextDestroyed( ) method when the servlet context is about to be shut down, such as when a web application is stopped prior to being reloaded.

Tomcat 4.1.24 initializes the servlet context listener prior to creating servlet instances, even if the application configures the servlet to be preloaded. Example 14-12 initializes the log4j system in the contextInitialized( ) method.

The deployment descriptor can instruct the servlet container to load a servlet instance and call its init( ) method at startup by including a load-on-startup element nested in the servlet element, as in:

<servlet>
    <servlet-name>logger</servlet-name>
    <servlet-class>
    com.jspservletcookbook.LoggerServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

The value of load-on-startup is an integer indicating the order in which the container loads the servlet.

In the contextInitialized( ) method, the listener configures log4j using the file specified by a context-param element in web.xml:

<context-param>
    <param-name>logger-config</param-name>
    <param-value>servletLog.properties</param-value>
</context-param>

This log4j configuration file (servletLog.properties) is located in the WEB-INF/classes directory. The listener then logs its messages to the console and to a file when the web application starts up or is shut down. Example 14-13 shows the configuration file the listener uses for log4j.

Example 14-13. Log4j configuration file used by the servlet context listener
log4j.rootLogger=DEBUG, cons
log4j.logger.com.jspservletcookbook=, myAppender

log4j.appender.cons=org.apache.log4j.ConsoleAppender

#configure the 'myAppender' appender

log4j.appender.myAppender=org.apache.log4j.RollingFileAppender
log4j.appender.myAppender.File=h:/home/example.log
log4j.appender.myAppender.MaxBackupIndex=1
log4j.appender.myAppender.MaxFileSize=1MB

log4j.appender.cons.layout=org.apache.log4j.SimpleLayout
log4j.appender.myAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.myAppender.layout.ConversionPattern=
%-5p Logger:%c{1} Date: %d{ISO8601} - %m%n

The listener gets a logger with this code:

log = Logger.getLogger(ContextLogger.class);

This names the logger after the class com.jspservletcookbook.ContextLogger. Therefore, in the log4j naming scheme, the listener's logger inherits the appender that Example 14-13 defines for the logger com.jspservletcokbook. This is because the configuration does not define a logger for com.jspservletcookbook.ContextLogger; consequently, the listener's logger inherits the next defined logger available: com.jspservletcookbook. The com.jspservletcookbook logger has a console appender and a file appender.

As a result, the servlet context listener sends its log messages to the console and the h:/home/example.log file. Example 14-13 has different layouts for the console and file appenders. The listener's console messages look like this:

INFO - ServletContext shut down: The home web application
INFO - ServletContext ready: The home web application

The log file messages have a different format:

INFO  Logger:ContextLogger Date: 2003-05-12 16:45:20,398 - ServletContext shut down: 
The home web application
INFO  Logger:ContextLogger Date: 2003-05-12 16:45:20,999 - ServletContext ready: The 
home web application

The format of these messages consists of the name of the logging level (e.g., INFO), the logger name, the date of the log request, and the message itself.

See Also

Recipe 14.2 on downloading and setting up log4j; Recipe 14.3 on using a log4j logger without a properties file; Recipe 14.4 on adding an appender to the root logger; Recipe 14.5 on using a pattern layout with a logger's appender; Recipe 14.6 on using a logger with a JSP; Recipe 14.8 on using log4j with session event listeners; the log4j download site: http://jakarta.apache.org/log4j/docs/download.html; the log4j Javadoc page: http://jakarta.apache.org/log4j/docs/api/index.html; the log4j project documentation page: http://jakarta.apache.org/log4j/docs/documentation.html.

    [ Team LiB ] Previous Section Next Section