Section B.2. Apache Log4J


B.2. Apache Log4J

Apache 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:


Configurable Destinations

Log4J logs messages to different output destinations, including files, JMS, and a DBMS.


Log Levels

Log4J has logging levels that enable you to configure which messages are logged to the output destination. For example, if debug-level logging is enabled, Log4J logs debug and higher level messages, and ignores trace-level messages.


Powerful Formatting

The formatting classes enable developers to specify the look and feel of logging messages.

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 Concepts

Log4J's key classes and interfaces include:


Logger

Log4J's main class. Logger logs messages to an Appender based on the message's logging level.


Appender

An Appender sends logging messages to a particular destination. Here are some of the Appender interface's concrete implementations:


JDBCAppender

Stores logging messages in a database table.


FileAppender

Writes logging messages to a file.


DailyRollingFileAppender

Writes logging messages to a file that is rolled over at a user-defined interval. Most people let the log file roll over every 24 hours so you have a separate log file for each day.


JMSAppender

Publishes logging messages to a JMS Topic.


SMTPAppender

Sends an email message that contains a logging message.


Layout

An Appender uses a Layout to format a logging message. Here are some of the Layout interface's concrete implementations:


SimpleLayout

Creates log messages that consist of the log level followed by a dash, and then the message itself. For example:

 FATALSomething went terribly wrong. 


HTMLLayout

Outputs log messages into an HTML table.


PatternLayout

Formats log messages based on a conversion pattern.

B.2.2. PatternLayout

PatternLayout 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.

Table B-1. Log4J PatternLayout

Pattern

Meaning

%c

Category of the log message.

%C

Fully qualified class name of the caller (caution: extremely slow).

%d

Date of the log message. This uses the default ISO 8601 format (YYYY-mm-dd HH:mm:ss,SSS) if none is specified.

%F

File name from where the logging request was issued (caution: extremely slow).

%L

Line number from where the logging request was issued (caution: extremely slow).

%m

The message text.

%M

Method name from where the logging request was issued (caution: extremely slow).

%n

Line separatorthis is Operating System neutral.

%p

Log level (priority) of the log message.

%%

A single percent sign.


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 File

Log4J 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:

  • Non-Java applications can work with XML files.

  • Most people prefer the XML configuration file rather than the properties file.

There are two options for configuring Log4J with JBoss:

  • Modify JBoss' log4j.xml file (located in the conf directory within the JBoss server configurationfor the JAW Motors application, this is in $JBOSS_HOME/server/default/conf).

  • Create an application-specific log4j.xml.

Modifying JBoss' log4j.xml file is undesirable for the following reasons:

  • You don't want to co-mingle your application-specific log messages with JBoss' log messages because your messages will be harder to find.

  • The JBoss log4j.xml file contains JBoss-specific Log4J setup details that you don't care about.

  • You have to make the same changes for your application to the JBoss log4j.xml file every time you upgrade JBoss.

  • You could copy the JBoss log4j.xml to your project directories, modify it with your application setup, and then include this file as part of application deployment. However, you still need to change your local version of log4j.xml whenever you upgrade JBoss.

  • Using the JBoss log4j.xml file ties an application to JBoss.

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:

  • We use a ClassLoader to locate the file.

  • We don't know if the configuration file comes before or after JBoss' log4j.xml file on the CLASSPATH, so we don't know which file (ours or JBoss') the ClassLoader will use.

  • Using a different file name guarantees that the ClassLoader loads our Log4J XML configuration file.

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 DailyRollingFileAppender logs messages using the specified format to a file defined as ${log4j.log.dir}/jbossatwork.log. We use a property because we don't want to hardcode the log file's directory path. At midnight, Log4J closes the previous day's log file (tagging it with the date) and creates a new one for the next day. The property log4j.log.dir is a System property that specifies the directory where the log file resides. Log4J looks in System Properties to find the value for any properties mentioned in a Log4J XML configuration file. The log4j.log.dir property can be set in one of two ways:

    • By passing in the value of the log4j.log.dir property as a -D option on the Java command line in the JBoss startup script (run.bat or run.sh). You can pass in the value by adding the following code to the JAVA_OPTS environment variable (the script uses JAVA_OPTS to build the Java command line):

       Dlog4j.log.dir=C:\rev2\logs 

    • But this has the same drawbacks (see above) as the JBoss log4j.xml.

    • By putting the log4j.log.dir property in a property file and including it in the application's CLASSPATH. The JAW Motors application specifies log4j.log.dir in a property file, log4j.extra.properties (which resides in common/conf). This properties file is deployed in a Common JAR that resides in an EAR file. The Initialization Servlet (see the Initialization Servlet section) then adds the log4j.log.dir property to System Properties at runtime before initializing Log4J. This type of deployment removes the tight coupling between the application and JBoss.

  • ConsoleAppender logs messages by using the specified format to System.out (the default setting).

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.properties
 log4j.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:


com.jbossatwork

By using com.jbossatwork (the JAW Motors application's root package name) as the category name, Log4J sends all messages from the JAW Motors application's classes to the "ROLLING" appendera DailyRollingAppender that uses the jbossatwork.log file (in the directory specified by log4j.log.dir) as its output destination. For the com.jbossatwork category, Log4J logs only messages with a logging level of INFO or higher.


org.apache

By using org.apache (the Apache Project's root package name) as the category name, Log4J sends all messages from the Apache Project's classes to the Root Category. In this case, Log4J logs only messages with a logging level of WARN or higher.


root

The Root Category has no name and is the default for messages that don't match any other Category. For the Root Category, Log4J logs only messages with a logging level of WARN or higher to the "STDOUT" appenderthis is a ConsoleAppender that uses Standard Output (the terminal) as its output destination.

B.2.4. Log4J Initialization

You can initialize Log4J with JBoss in several ways:

  • Several options include setting the log4j.configuration system property with the -D option on the Java command line in the JBoss startup script (run.bat or run.sh) by adding the following to the JAVA_OPTS environment variable (the script uses JAVA_OPTS to build the Java command line):

      -Dlog4j.configuration=jbossatwork-log4j.xml 

  • Use the CLASSPATH. In this case, you put the Log4J configuration file on the application CLASSPATH and access the file with a ClassLoader at application startup.

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 Servlet

JBoss 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.java
 package 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:

  • Calls SystemPropertiesUtil.addToSystemPropertiesFromPropsFile( ) to add the properties from the log4j.extra.properties file to the System Properties.

  • Calls Log4jConfigurator.setup( ) to configure Log4J with our Log4J configuration file, jbossatwork-log4j.xml.

J2EE Design Notes

We could have used a JMX MBean (Managed Bean) to initialize the JAW Motors application instead of using a Servlet. An MBean is similar to an initialization Servlet because both run when JBoss starts up. An MBean differs from an initialization Servlet because an MBean enables you to use the JMX Console to change settings such as Log4J Levels while the application is still running. We chose an initialization Servlet because we didn't need to dynamically change application properties and settings at runtime. If you need this level of flexibility, though, an MBean would be the best technology for the job.


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.



JBoss at Work. A Practical Guide
JBoss at Work: A Practical Guide
ISBN: 0596007345
EAN: 2147483647
Year: 2004
Pages: 197

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net