Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Application logging in WebSphere Application Server Community Edition

Using java.util.logging, Log4j and SLF4j

Phani Madgula (mabalaji@in.ibm.com), Software Developer, IBM
author image
Phani is currently working for WebSphere Application Server Community Edition support at India Software Labs (ISL). He has been actively involved in many projects related to migrating applications from other application servers to WebSphere Application Server Community Edition. He has 5 years experience at IBM. He worked in various product teams including WebSphere Application Server Community Edition, WebSphere Business Integration Adapters and DB2. He has experience in developing JEE applications, product support, and database administration. He is an Oracle9i certified professional.

Summary:  WebSphere Application Server Community Edition provides several ways to configure application logging, using java.util.logging, Log4j and SLF4j APIs. Though the steps to configure these logging services are to large extent independent of any application server, WebSphere Application Server requires certain tweaks to get your desired logging behavior. This tutorial walks you through these tweaks coupled with sample applications. WebSphere® Application Server Community Edition is freely available for download, so you can get started in just a few minutes.

Date:  25 Mar 2009
Level:  Intermediate PDF:  A4 and Letter (350 KB | 29 pages)Get Adobe® Reader®

Activity:  42332 views
Comments:  

Community Edition nuances and getting the most from Log4j

Log4j is an open source library for logging services from the Apache Software Foundation. Log4j is widely used in the open source community, including some big names like Apache Geronimo, JBoss, etc. Log4j's architecture revolves around three main concepts: Loggers, Appenders, and Layouts.

Applications first call Logger objects to initiate the logging of a message. When given a message to log, loggers generate LogEvent objects to wrap the given message. The loggers then pass on the LogEvents objects to their associated Appenders. The Appenders send the information contained by the LogEvents to specified output destinations. For example, a ConsoleAppender writes the information to System.out, and a FileApppender writes it to a log file. Before sending the information to the destination, the Appenders can use Layouts to create a text representation of the information in a desired format. For example, Appenders can use XMLLayout that formats the log messages as XML strings.

The LoggingEvents are assigned a level that indicates its priority. The default levels are (from highest to lowest):

  • OFF
  • FATAL
  • ERROR,
  • WARN
  • INFO
  • DEBUG
  • ALL

Loggers and Appenders are assigned a level. If a LogEvent has the log level as WARN and the Appender's log level is ERROR, the Appender will not write the LogEvent. In this way, you can control the amount of log output.

All Loggers in Log4j have a name. Log4j organizes Logger instances in a hierarchical, tree structure, according to the names, as in the packaging namespace in the Java language. The Log4j documentation says

"A Logger is said to be an ancestor of another Logger if its name followed by a dot is a prefix of the descendant Logger name. A Logger is said to be a parent of a child Logger if there are no ancestors between itself and the descendant Logger".

For example, a Logger named com.ibm is said to be the child of the com Logger. The com.ibm.wasce Logger is the child of the com.ibm Logger and the grandchild of the com Logger. If a Logger is not explicitly assigned a level, it uses the level of its closest ancestor that has been assigned a level. Loggers inherit Appenders from their ancestors, although they can also be configured to use only Appenders that are directly assigned to them.

You configure all the Loggers, Appenders and Layouts in the log4j.properties or log4j.xml file. Log4j libraries first look for log4j.xml file and then log4j.properties file in the classpath to configure the logging service.

From the above discussion, you might think that Log4j is similar to java.util.logging. Of course, they are conceptually the same, but Log4j can do more than java.util. Handlers in java.util.logging perform the same tasks as Appenders in Log4j. The Formatters in java.util.logging perform the same task as Layouts in Log4j. However, java.util.logging has only four Handlers, whereas Log4j has a dozen Appenders. In addition, Log4j offers a rich set of Layouts where java.util.logging offers only SimpleFormatter and XMLFormatter. Some of the Appenders available in Log4j are:

  • FileAppender: Appends log events to a file.
  • RollingFileAppender: Extends FileAppender to backup the log files when they reach a certain size.
  • ConsoleAppender: Appends log events to System.out or System.err using a layout specified by the user. The default target is System.out
  • SocketAppender: Sends LoggingEvent objects to a remote a log server, usually a SocketNode.
  • JMSAppender: A simple Appender that publishes events to a JMS Topic. The events are serialized and transmitted as the JMS message type ObjectMessage.
  • NTEventLogAppender: Append to the NT event log system.

Log4j includes XMLLayout, SimpleLayout, TTCCLayout, HTMLLayout. For descriptions of various Appenders and Layouts, see the Log4j documentation.

In this section, we show how to use Log4j in applications deployed on Community Edition. Community Edition, by default, uses the following log4j configuration files:

  • <wasce_home>/var/log/server-log4j.properties: This file configures Appenders and Layouts for the server components as well as applications deployed on the server. This file configures a ConsoleAppender and a RollingFileAppender. The ConsoleAppender logs to System.out and the RollingFileAppender logs to the <wasce_home>/var/log/server.log file. The default logging is WARN. It also overrides log levels for various Loggers in the properties file.
  • <wasce_home>/var/log/deployer-log4j.properties: This file configures logging service for the deployer. The deployer component is invoked when any applications are deployed using the command line deployer.
  • <wasce_home>/var/log/client-log4.properties: This file configures logging service for a Java EE application client.

In this section, we will configure Log4j in the following ways

  1. Using the default server Log4j configuration
  2. Setting up Log4j at the application level

Using the default server Log4j configuration

As described earlier, server components as well as applications deployed on Community Edition use the configuration in <wasce_home>/var/log/server-log4j.properties. We will use the modified EMPDemo sample that has Log4j for logging. It also uses the default configuration available in Community Edition. The sample contains the same EMPDemo servlet modified for logging using Log4j API. Listing 9 shows the modified EMPDemo, with the logging statements marked in bold. The servlet obtains the Logger and sets the log level to ALL.


Listing 9. Modified EMPDemo using the Log4j API
Logger logger = Logger.getLogger(EMPDemo.class.getName());
logger.setLevel(Level.ALL);
Connection con = null;
Statement stmt = null;
		
PrintWriter out = response.getWriter();
		
logger.info("Created the PrintWriter on the Response object");
		
try {
    Context initContext = new InitialContext();
    Context envContext  = (Context)initContext.lookup("java:comp/env");
    logger.info("Got environment context: " +envContext);
    DataSource ds = (DataSource)envContext.lookup("jdbc/DataSource");
    logger.info("Got DataSource: " +ds.toString());
    con = ds.getConnection();
    logger.info("Got Connection: " +con.toString() +"\n");

    stmt = con.createStatement();	
    logger.info("Created the statement: " +stmt);
    ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
    logger.info("Gto the result set: " +rs);
    logger.info("Table EMP after SELECT:");
	
out.println("Your EMP table contains the following entries:<BR>");
		
out.println("<table>");
out.println("<tr>");
out.println("<th>Empno</th>");
out.println("<th>Name</th>");
out.println("<th>Job</th>");
out.println("<th>Manager</th>");
out.println("<th>Salary</th>");
    out.println("<th>Commission</th>");
    out.println("<th>Deptno</th>");
    out.println("</tr>");

    while (rs.next()) {
        String emp = rs.getString("EMPNO");
        String name  = rs.getString("ENAME");
        String job = rs.getString("JOB");
        String mgr = rs.getString("MGR");
        String sal = rs.getString("SAL");
        String comm = rs.getString("COMM");
        String dept = rs.getString("DEPTNO");

        out.println("<tr>");
        out.println("<td>"+emp+"</td>");
        out.println("<td>"+name+"</td>");
        out.println("<td>"+job+"</td>");
        out.println("<td>"+mgr+"</td>");
        out.println("<td>"+sal+"</td>");
        out.println("<td>"+comm+"</td>");
        out.println("<td>"+dept+"</td>");
        out.println("</tr>");
				
        logger.info(emp + "   " + name + "   " + job);
        logger.info("   " + mgr + "   " + dept);

    out.println("</table>");
			
    rs.close();
    stmt.close();
    con.close();
	
    logger.debug("Debug");
    logger.info("Info");
    logger.warn("Warn");
    logger.error("Error");
    logger.fatal("Fatal");

}
catch(java.lang.Exception e) {
			
    e.printStackTrace();
    logger.fatal(e.getClass().getName());
    logger.fatal(e.getMessage());

}

Follow these steps to deploy and run the application:

  1. From the sample download, unzip the EMPDemo sample into a directory. The war file name is EMPdemo-Log4jLogging1.war.
  2. Deploy the application.
    <wasce_home>/bin>deploy --user system --password manager deploy Log4jLogging1.war.
  3. Access the EMPDemo servlet by pointing your browser to http://localhost:8080/EMPdemo-log4j1/EMPDemo. The servlet shows the rows from the employee table on the browser window.

Observe the console window to note that only the log messages shown in Listing 10 are logged. This is because the ConsoleAppender’s log level is WARN by default (in the server-log4j.properties). So, the log messages whose log level is WARN or above are logged in the console.


Listing 10. Log messages in the console
14:13:31,687 WARN  [EMPDemo] Warn
14:13:31,687 ERROR [EMPDemo] Error
14:13:31,687 FATAL [EMPDemo] Fatal

Open the <wasce_home>/var/log/server.log file to observe that all the log messages have been logged. This is because the log level of the FileAppender is TRACE by default. Hence it has logged all the messages. Listing 11 shows the logged messages:


Listing 11. server.log file
14:13:31,687 INFO  [EMPDemo] 
 Created the PrintWriter on the Response object
14:13:31,687 INFO  [EMPDemo] 
 Got environment context: 
 org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@5b9e5b9e
14:13:31,687 INFO  [EMPDemo] 
 Got DataSource: org.tranql.connector.jdbc.DataSource@8660866
14:13:31,687 INFO  [EMPDemo] 
 Got Connection: org.tranql.connector.jdbc.ConnectionHandle@a1e0a1e
14:13:31,687 INFO  [EMPDemo] 
 Created the statement: org.tranql.connector.jdbc.StatementHandle@c980c98
14:13:31,687 INFO  [EMPDemo] 
 Got the result set: org.tranql.connector.jdbc.ResultSetHandle@11221122

14:13:31,687 INFO  [EMPDemo] Table EMP after SELECT:
14:13:31,687 INFO  [EMPDemo] 1   PHANI   SSE
14:13:31,687 INFO  [EMPDemo]    NIKHIL   100
14:13:31,687 INFO  [EMPDemo] 2   JOE   SSE
14:13:31,687 INFO  [EMPDemo]    NIKHIL   100
14:13:31,687 INFO  [EMPDemo] 3   JOHN   SSE
14:13:31,687 INFO  [EMPDemo]    BOB   200
14:13:31,687 DEBUG [EMPDemo] Debug
14:13:31,687 INFO  [EMPDemo] Info
14:13:31,687 WARN  [EMPDemo] Warn
14:13:31,687 ERROR [EMPDemo] Error
14:13:31,687 FATAL [EMPDemo] Fatal 


Setting up Log4j at the application level

Sometimes you might want to configure Log4j at the application level, ignoring the server-level configuration. You can do this by packaging the Log4j libraries and log4j.properties configuration with the application itself, and deploying the application. However, there is a hitch here -- Community Edition uses a “parent first” classloader policy. This means, if the classes are available in parent classloader, they will be loaded from the parent classloader. Since the Log4j is used by server components and is loaded by a classloader (which is higher in the classloader hierarchy) Log4j configured at the server level is always used even if Log4j libraries and log4.properties file are packaged with the application.

To resolve this issue, we need to hide Log4j from the parent classloader and make it always load from the application classloader. To hide Loh4j, you specify <hidden-classes> for the Log4j classes in the Community Edition application deployment plan. For information about other various classloader policies available in Community Edition, see this technote.
This section illustrates how to configure Log4j at the application level. We use the same sample as in the previous section. However, we modify the Community Edition application deployment plan (geronimo-web.xml) to hide the Log4j classes. Listing 12 shows the modified Geronimo deployment plan , with the relevant portion of the plan marked in bold.


Listing 12. Modified geronimo-web.xml deployment plan
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<web:web-app xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" 
    xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" 
    xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" 
    xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" 
    xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" 
    xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" 
    xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" 
    xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1"
    xmlns:pers="http://java.sun.com/xml/ns/persistence" 
    xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0">
    <dep:environment>
        <dep:moduleId>
            <dep:groupId>com.ibm.wasce.samples</dep:groupId>
            <dep:artifactId>EMPdemo-log4j-2</dep:artifactId>
            <dep:version>2.1.0.0</dep:version>
            <dep:type>war</dep:type>
        </dep:moduleId>
        <dependencies>
            <dependency>
                <groupId>console.dbpool</groupId>
                <artifactId>EMPLOYEE_DS</artifactId>
            </dependency>
        </dependencies>
        <hidden-classes>
  	<filter>org.apache.log4j</filter>
       </hidden-classes>
    </dep:environment>
    <web:context-root>/EMPdemo-log4j2</web:context-root>
    <name:resource-ref>
        <name:ref-name>jdbc/DataSource</name:ref-name>
        <name:resource-link>EMPLOYEE_DS</name:resource-link>
    </name:resource-ref>
</web:web-app>

Also, we copy the log4j.properties file into the WEB-INF/classes directory and copy log4j-1.2.14.jar in to the WEB-INF/lib directory of the EMPDemo application. Listing 13 shows the log4j.properties file:


Listing 13. The log4j.properties file
log4j.logger.com.ibm.sample=debug,applog

log4j.appender.applog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.applog.File=C:/temp/applevellogging/Log4J/applog1.log
log4j.appender.applog.layout=org.apache.log4j.PatternLayout

log4j.appender.applog.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}] %m%n

This properties file defines a Logger for the servlet, and sets the Log level to DEBUG. But the servlet overrides this value to make it ALL. It also defines a DailyRollingFileAppender that logs messages to the C:/temp/applevellogging/Log4J/applog1.log file. The Layout used by the Appender is the standard Community Edition layout used in the server-log4j.properties file. Follow these steps to deploy the application.

  1. From the sample download, unzip the modified Web application. The WAR file name is EMPdemo-Log4jLogging2.war.
  2. Deploy the application.
    <wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-Log4jLogging2.war
  3. Access the EMPDemo servlet by pointing a browser to http://localhost:8080/EMPdemo-log4j2/EMPDemo. The servlet shows the rows from the employee table in the browser.

Note that no messages have been logged in server console or in the server.log file, because we have overridden the server level Log4j configuration and configured it at the application level. Moreover, the application creates the C:/temp/applevellogging/Log4J/applog1.log file and logs the messages in this file. Listing 14 shows the messages logged in the file:


Listing 14. Messages in the applog1.log file
15:18:36,078 INFO  [EMPDemo] 
 Created the PrintWriter on the Response object
15:18:36,093 INFO  [EMPDemo] 
 Got environment context: 
 org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@d760d76
15:18:36,093 INFO  [EMPDemo]
 Got DataSource: org.tranql.connector.jdbc.DataSource@32a232a2
15:18:36,109 INFO  [EMPDemo]
 Got Connection: org.tranql.connector.jdbc.ConnectionHandle@61e461e4
15:18:36,109 INFO  [EMPDemo]
 Created the statement: org.tranql.connector.jdbc.StatementHandle@67206720
15:18:36,109 INFO  [EMPDemo]
 Got the result set: org.tranql.connector.jdbc.ResultSetHandle@6f9a6f9a

15:18:36,109 INFO  [EMPDemo] Table EMP after SELECT:
15:18:36,109 INFO  [EMPDemo] 1   PHANI   SSE
15:18:36,109 INFO  [EMPDemo]    NIKHIL   100
15:18:36,109 INFO  [EMPDemo] 2   JOE   SSE
15:18:36,109 INFO  [EMPDemo]    NIKHIL   100
15:18:36,109 INFO  [EMPDemo] 3   JOHN   SSE
15:18:36,109 INFO  [EMPDemo]    BOB   200
15:18:36,109 DEBUG [EMPDemo] Debug
15:18:36,109 INFO  [EMPDemo] Info
15:18:36,109 WARN  [EMPDemo] Warn
15:18:36,109 ERROR [EMPDemo] Error
15:18:36,109 FATAL [EMPDemo] Fatal


4 of 9 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Open source
ArticleID=376844
TutorialTitle=Application logging in WebSphere Application Server Community Edition
publish-date=03252009
author1-email=mabalaji@in.ibm.com
author1-email-cc=