[ Team LiB ] |
![]() ![]() |
Recipe 14.6 Using log4j in a JSPProblemYou want to include logging statements in a JSP. SolutionDesign a custom tag that uses log4j to initiate logging messages. DiscussionA custom tag is an XML element that you invent or design for use in a JSP. In other words, the JSP container does not provide the custom actions; the web developer himself designs the Java classes that provide the tag functionality. A custom tag or action can be used to implement log4j logging functionality in JSPs. In this recipe, I show:
Example 14-9 shows the Java class LoggerTag on which the cbck:log tag is based. Each custom action is actually driven behind the scenes by one or more Java classes. In this case, LoggerTag is like a JavaBean that wraps the log4j classes, which we import at the top of the tag class. Custom JSP actions are a complex topic, so I explain this tag by focusing mainly on its log4j features. See Chapter 22 to help fill in the missing spaces in your own knowledge about custom tag development. Example 14-9. A custom tag that uses log4jpackage com.jspservletcookbook; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import java.lang.reflect.Method; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; public class LoggerTag extends BodyTagSupport { private Logger log = null; private String configFile = null; private String level = null; private static final String[] LEVELS = { "debug","info","warn","error","fatal"}; public void setConfigFile(String fileName){ this.configFile = fileName; } public void setLevel(String level){ this.level = level; } public int doEndTag( ) throws JspException { String realPath = pageContext.getServletContext( ).getRealPath("/"); String fileSep = System.getProperty("file.separator"); if (realPath != null && (!realPath.endsWith(fileSep))){ realPath = realPath + fileSep;} //configure the logger if the user provides this optional attribute if (configFile != null) PropertyConfigurator.configure(realPath + "WEB-INF/classes/" + configFile); //throw an exception if the tag user provides an invalid level, //something other than DEBUG, INFO, WARN, ERROR, or FATAL level = level.toLowerCase( ); if (! contains(level)) throw new JspException( "The value given for the level attribute is invalid."); //The logger has the same name as the class: //com.jspservletcookbook.LoggerTag. Therefore, it inherits its //appenders from a logger defined in the config file: //com.jspservletcookbook log = Logger.getLogger(LoggerTag.class); String message = getBodyContent( ).getString( ).trim( ); Method method = null; try{ method = log.getClass( ). getMethod(level,new Class[]{ Object.class }); method.invoke(log,new String[]{message}); } catch (Exception e){} return EVAL_PAGE; } // doEndTag public void release( ){ //release resources used by instance variables log = null; configFile = null; level = null; }// release private boolean contains(String str){ for (int i = 0; i < LEVELS.length; i++){ if(LEVELS[i].equals(str)) return true; } return false; }// contains } The LoggerTag extends the javax.servlet.jsp.tagext.BodyTagSupport class, which is designed for custom actions that process body content, or the text that may appear between opening and closing tags. The tag attributes, a required attribute named level and the configFile optional attribute, are handled like JavaBean properties: with "setter" methods (e.g., public void setLevel(String level)). The doEndTag( ) method does most of the important work for the tag: Example 14-10 shows the TLD, which conveys tag specifics to the JSP container, such as whether an attribute is required or optional. The tag library associated with this TLD describes only the cbck:log tag. The TLD files must be located in WEB-INF or a subdirectory thereof, or inside of the META-INF directory of a JAR that is placed in WEB-INF/lib. Example 14-10. The TLD for the custom logger tag<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>cbck</short-name>
<uri>jspservletcookbook.com.tags</uri>
<description>Cookbook custom tags</description>
<tag>
<name>log</name>
<tag-class>com.jspservletcookbook.LoggerTag</tag-class>
<body-content>JSP</body-content>
<description>This tag uses log4j to log a message.</description>
<attribute>
<name>configFile</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<description>
This attribute provides any configuration filename for the
logger. The file must be located in
WEB-INF/classes.
</description>
</attribute>
<attribute>
<name>level</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<description>This attribute provides the level for the log request.
</description>
</attribute>
</tag>
</taglib>
Example 14-11 shows the logger.jsp page and how the custom action can be used. Example 14-11. A JSP uses a log custom action to access log4j<%@page contentType="text/html"%> <%@ taglib uri="jspservletcookbook.com.tags" prefix="cbck" %> <html> <head><title>A logging JSP</title></head> <body> <h2>Here is the logging statement</h2> <cbck:log level="debug"> Debug message from logger.jsp </cbck:log> Debug message from logger.jsp </body> </html> First, the page uses the taglib directive to declare the tag library that contains our custom action. Example 14-10 shows the TLD file, an XML file that describes the properties of a tag library's various tags. Chapter 22 describes TLDs in more detail. The cbck:log custom action allows a developer to log a message from the JSP by nesting the message text within the cbck:log tag (i.e., the body content of the tag is the log message). The cbck part of the tag is the prefix that the taglib directive declared. The log part is the name of the tag. The tag allows the developer to declare the logging level with the custom action's level attribute.
For this tag, assume that you want to decide which logging level to use, and thus pass in a value for the level attribute. The tag class does not know whether the message will request a logging level of DEBUG, INFO, WARN, ERROR, or FATAL. Since the logger's methods in log4j use the same name as the levels, we can dynamically call the proper method based on the value of the level attribute. This is the purpose of the code: method = log.getClass( ). getMethod(level,new Class[]{ Object.class }); method.invoke(log,new String[]{message}); We get a java.lang.reflect.Method object that is named either DEBUG, INFO, WARN, ERROR, or FATAL, and then invoke that method calling method.invoke, passing in the log message from the JSP page. A configuration filename is not required for this tag, so how does log4j know how and where to log the message? This tag assumes that a servlet has already initialized the log4j system for the web application, which is typical for the use of log4j in a web environment. The configuration file is the one described by Recipe 14.4 and shown in Example 14-5.
That configuration file created a logging mechanism that sends messages to the console and a file, so that is where the custom tag's messages go. For example, running logger.jsp displays a message on the console: DEBUG - Debug message from logger.jsp The tag's logger writes the following message in the file example.log: DEBUG Logger:LoggerTag Date: 2003-05-12 12:53:13,750 - Debug message from logger.jsp If you want to include your own configuration file, you can include a configFile attribute when using the custom tag. The tag will configure the logger using that file instead of any previously initialized one: if (configFile != null) PropertyConfigurator.configure( pageContext.getServletContext( ).getRealPath("/") + "WEB-INF/classes/" + configFile); See AlsoRecipe 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.7 and Recipe 14.8 on using log4j with application 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 ] |
![]() ![]() |