B.2. Apache Log4JApache Log4J, a powerful logging framework, is the de-facto standard in the Java Open Source community. Recently promoted from the Jakarta project, Log4J has done so well that it has been ported to C, C++, Perl, PHP, Python, .NET, and Ruby. Log4J provides the following features:
Because a thorough discussion of Log4J is outside the scope of this book, please see the References section for complete documentation. B.2.1. Log4J Core ConceptsLog4J's key classes and interfaces include:
B.2.2. PatternLayoutPatternLayout is the most common way to format messages, so that's what we use for the JAW Motors application. Table B-1 shows some of the most common conversion patterns.
The JAW Motors application uses the following conversion pattern to output messages to a log file: %d %-5p [%c] - %m%n Here is a sample message from the log file: 2005-06-06 17:24:02,923 INFO [com.jbossatwork.InitServlet] - Testing Logging Setup ... This message consists of: the date/time (%d), the logging level (%-5p), the category ([%c]) of the message (this is configured as the class name), a dash, the message text (%m), and the line separator (%n). Example B-3 shows the call from the InitServlet (see the Initialization Servlet section) that generated the message. Example B-3. InitServlet.java log.info("Testing Logging Setup ..."); B.2.3. Log4J Configuration FileLog4J configures the Appender (destination) and Layout (format) for Log4J messages in an external file. Originally, Log4J used a Java properties file (log4j.properties), but now the preferred way is to use an XML configuration file , log4j.xml. The JAW Motors application uses log4j.xml file because:
There are two options for configuring Log4J with JBoss:
Modifying JBoss' log4j.xml file is undesirable for the following reasons:
The JAW Motors application uses its own Log4J XML configuration file, jbossatwork-log4j.xml, to keep its configuration and log messages separate from JBoss. We named our file jbossatwork-log4j.xml rather than log4j.xml because:
Example B-4 shows the Log4J XML configuration file for the JAW Motors application. Example B-4. jbossatwork-log4j.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true" > <appender name="STDOUT" > <param name="Target" value="System.out"/> <param name="Threshold" value="INFO"/> <layout > <param name="ConversionPattern" value="%d %-5p [%c] - %m%n"/> </layout> </appender> <appender name="ROLLING" > <param name="File" value="${log4j.log.dir}/jbossatwork.log"/> <layout > <param name="ConversionPattern" value="%d %-5p [%c] - %m%n"/> </layout> </appender> <category name="com.jbossatwork"> <priority value="DEBUG"/> <appender-ref ref="ROLLING"/> </category> <category name="org.apache"> <priority value="WARN"/> </category> <root> <priority value="WARN"/> <appender-ref ref="STDOUT"/> </root> </log4j:configuration> The above jbossatwork-log4j.xml file defines two Appenders:
The log4j.extra.properties file is an application-specific properties file that holds extra properties to configure Log4J. The log4j.extra.properties file resides in the appb project's common/conf subdirectory and looks like Example B-5. Example B-5. log4j.extra.propertieslog4j.log.dir=C:/rev2/logs The log4j.log.dir property represents the directory where the JAW Motors application's log file resides. You'll want to set the log4j.log.dir property to a valid path on your filesystemif you don't do this, Log4J will not log your messages. This log directory MUST exist before starting JBoss or Log4J can not create the logfile. However, you don't have to create the directory because appb Ant build script does it for you. The log4j.log.dir property's key and value must be added to System Properties so Log4J can configure itself properly by using jbossatwork-log4j.xml (which uses log4j.log.dir as a System Property to configure its File Appender). A Category logs messages to one or more Appenders. The JAW Motors application's jbossatwork-log4j.xml file (which resides in the appb project's common/conf sub-directory) defines three Categories:
B.2.4. Log4J InitializationYou can initialize Log4J with JBoss in several ways:
Using the -D mechanism is unacceptable because it forces you to modify the JBoss startup script (JBOSS_HOME/bin/run.bat or run.sh)see the Log4J Configuration File section for a full discussion on the problems with modifying JBoss files. Getting a resource on the CLASSPATH with a ClassLoader is a better option because it separates an application's deployment (EAR/WAR/EJB JAR) from the application server. B.2.5. Initialization ServletJBoss loadsinstantiates the Servlet and invokes init( )the InitServlet at startup before invoking any other Servlet or other J2EE component. The InitiServlet extends javax.servlet.GenericServlet because it doesn't respond to HTTP requestsits only purpose is to set up the JAW Motors application. Initializing Log4J with a Servlet that executes at startup time sets up Log4J for all J2EE components in the application. The following extra settings in web.xml (Example B-6) ensure that InitServlet runs at startup time. Example B-6. web.xml ... <servlet> <servlet-name>InitServlet</servlet-name> <servlet-class>com.jbossatwork.InitServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> ... We've already seen the basic <servlet> tags in the Web Application Chapter. Any positive integer value (0 or greater) for the <load-on-startup> tag causes JBoss to instantiate InitServlet and invoke its init( ) method when JBoss starts the web application. For further information on loading Servlets on startup, see one of the Servlet books in the References section. The Web Application Chapter showed how to use XDoclet tags for core Servlet deployment . In keeping with XDoclet-based development, the InitServlet now uses an additional attributeload-on-startup="1"on the @web.servlet XDoclet tag to generate the <load-on-startup> element in web.xml (Example B-7). Example B-7. InitServlet.javapackage com.jbossatwork; import javax.servlet.*; import java.io.*; import org.apache.commons.logging.*; import com.jbossatwork.util.*; /** * InitServlet sets up Log4J for the application. * * @web.servlet * name="InitServlet" * load-on-startup="1" * */ public class InitServlet extends GenericServlet { private Log log = LogFactory.getLog(InitServlet.class); private ServletContext servletContext; public void init( ) { servletContext = getServletContext( ); SystemPropertiesUtil.addToSystemPropertiesFromPropsFile( "log4j.extra.properties"); Log4jConfigurator.setup("jbossatwork-log4j.xml"); log.info("Testing Logging Setup ..."); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { } } Rather than putting all the low-level setup code in the InitServlet, the init( ) method defers to utility objects:
We've shown the Log4J Configuration file, the Initialization Servlet, and application-specific properties for setting up Log4J. Now let's look closely at the SystemPropertiesUtil utility class. |