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.
|
No comments:
Post a Comment