Thursday, October 22, 2009

Recipe 14.7 Logging Messages Using a Servlet Context Event Listener



[ Team LiB ]






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 ]



    No comments: