BEA Logo BEA WebLogic Application Integration 2.0

  BEA Home  |  Events  |  Solutions  |  Partners  |  Products  |  Services  |  Download  |  Developer Center  |  WebSUPPORT

 

   Application Integration Documentation   |   Application Integration Adapter Development Guide   |   Previous Topic   |   Next Topic   |   Contents   |   Index

The ADK Logging Toolkit

 

Logging is an essential feature of an adapter component. Most adapters are used to integrate different applications and do not interact with end users while processing data. Unlike the behavior of a front-end component, when an adapter encounters an error or warning condition, it cannot stop processing and wait for an end-user to respond.

With the ADK, logging adapter activity is accomplished by implementing a logging framework. This framework gives you the ability to log internationalized and localized messages to multiple output destinations. It provides a range of configuration parameters you can use to tailor message category, priority, format, and destination.

This section contains information on the following subjects:

 


Logging Toolkit

The ADK's logging toolkit allows you to log internationalized messages to multiple output destinations. The logging toolkit leverages the work of the open source project Apache Log4j. This product includes software developed by the Apache Software Foundation (http://www.apache.org/).

The logging toolkit is a container that wraps the necessary Log4j classes to provide added functionality for J2EE-compliant adapters. It is provided in the logtoolkit.jar file under: <WLAI_ROOT>/lib. This .jar file depends on DOM, XERCES, and Log4j 1.1.2. The XERCES dependency is satisfied by weblogic.jar and xmlx.jar provided in the WebLogic 6.0 distribution (<WL_HOME>/lib). The Application Integration distribution includes the required version of Log4j in (<WLAI_HOME>/resources/Log4j).

The Log4j package is distributed under the Apache Public License, a full-fledged open source license certified by the open source initiative. The latest Log4j version, including full-source code, class files and documentation can be found at the Apache Log4j Web site.

 


Logging Configuration File

Throughout this section, you will see references to and code snippets from the logging configuration file. This file is a .xml file that is identified by the adapter logical name; for example, BEA_WLS_DBMS_ADK.xml. It contains the base information for the four logging concepts discussed in Logging Concepts and can be modified for your specific adapter.

The ADK provides a basic logging configuration file, BEA_WLS_SAMPLE_ADK.xml, in <WLAI_HOME>/dev/sample/src. To modify this file for your adapter, run GenerateAdapterTemplate. This utility will customize the sample version of the logging configuration file with information pertinent to your new adapter and place the customized version in the new adapter's development environment. For more information on GenerateAdapterTemplate, see Creating a Custom Development Environment.

 


Logging Concepts

Prior to using the logging toolkit provided with the ADK, you should understand a few key concepts of the logging framework. Logging has four main components:

These components work together to enable you to log messages according to message type and priority, and to control at runtime how these messages are formatted and where they are reported.

Message Categories

Categories identify log messages according to criteria you defined and are a central concept of the logging framework. In the ADK, a category is identified by its name, such as BEA_WLS_SAMPLE_ADK.DesignTime.

Categories are hierarchically defined. That is, any category can inherit properties from parent categories. The hierarchy is defined thusly:

For example, BEA_WLS_SAMPLE_ADK.DesignTime is a descendant of BEA_WLS_SAMPLE_ADK, which is a descendant of the root category. For example:

ROOT CATEGORY
  |
  |->BEA_WLS_SAMPLE_ADK
       |
       |->BEA_WLA_SAMPLE.ADK.DesignTime 

The root category resides at the top of the category hierarchy; it always exists and it cannot be retrieved by name.

When you create categories, you should name them according to components in their adapter. For example, if an adapter has a design-time user interface component, the adapter could have a category, BEA_WLS_SAMPLE_ADK.DesignTime.

Message Priority

Every message has a priority that indicates its importance. Message priority is determined by the method on the ILogger interface used to log the message. In other words, calling the debug method on an ILogger instance generates a debug message.

The logging toolkit supports five possible priorities for a given message, as described in Table 5-1:

Table 5-1 Logging Toolkit Priorities


 

Priority

Description

AUDIT

Indicates an extremely important log message that relates to the business processing performed by an adapter. Messages with this priority will always be written to the log output.

ERROR

Indicates an error in the adapter. Error messages are internationalized/localized for the user.

WARN

Indicates a situation that is not an error, but could cause problems in the adapter. A warning message that is internationalized/localized for the user.

INFO

Indicates an informational message that is internationalized/localized for the user.

DEBUG

Indicates a debug message, which are used to determine how the internals of a component are working and are typically not internationalized.

The BEA_WLS_SAMPLE_ADK category has priority DEBUG because of the following child element:

<priority value='DEBUG' class='com.bea.logging.LogPriority'/>

The class for the priority must be com.bea.logging.LogPriority.

Assigning a Priority to a Category

You can assign a priority to a Category. If a given category is not assigned a priority, it inherits one from its closest ancestor with an assigned priority; that is, the inherited priority for a given category is equal to the first non-null priority in the category hierarchy, starting at the given category and proceeding upwards in the hierarchy towards the root category.

A log message will be output to the log destination if its priority is higher than or equal to the priority of its category. Otherwise, the message will not be written to the log destinations. A category without an assigned priority will inherit one from the hierarchy. To ensure that all categories can eventually inherit a priority, the root category always has an assigned priority. A log statement of priority p in a category with inherited priority q, is enabled if p >= q. This rule assumes that priorities are ordered as follows: DEBUG < INFO < WARN < ERROR < AUDIT.

Message Appenders

The logging framework allows an adapter to log to multiple destinations by using an interface called an appender. Log4j provides appenders for:

In addition, the ADK log toolkit provides a WebLogic appender that you can specify to output the log message to your WebLogic Server log.

A category may refer to multiple appenders. Each enabled logging request for a given category will be forwarded to all the appenders in that category, as well as the appenders higher in the hierarchy. In other words, appenders are inherited additively from the category hierarchy. For example, if a console appender is added to the root category, then all enabled logging requests will at least print on the console. If in addition a file appender is added to category "C," then enabled logging requests for C and C's children will print to a file and on the console. It is possible to override this default behavior so that appender accumulation is no longer additive by setting the additivity flag to false.

Note: If you've also added the console appender to directly to C, you will get two messages—one from C and one from the root—on the console. This is because the root category always logs to the console.

Listing 5-1 shows an appender for the WebLogic log:

Listing 5-1 Sample Code Showing an Appender for the WebLogic Log

<!-- 
  A WeblogicAppender sends log output to the WebLogic log.
  It can only be used if you are running inside WebLogic.
-->
<appender name="WebLogicAppender" class="com.bea.logging.WeblogicAppender">
      <!-- Use a basic LOG4J pattern layout -->
  <layout class="org.apache.Log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p %d{DATE} %c{4} %x - %m%n"/>
  </layout>      
  </appender>

Message Layout

By using Log4j, you can also customize the format of a log message. This is accomplished by associating a layout with an appender. The layout is responsible for formatting a log message while an appender directs the formatted message to its destination. The log toolkit typically uses the PatternLayout to format its log messages. The PatternLayout, part of the standard Log4j distribution, lets you specify the output format according to conversion patterns similar to the C language printf function.

For example, the PatternLayout with the conversion pattern %-5p%d{DATE} %c{4} %x - %m%n will output a message like:

AUDIT 21 May 2001 11:00:57,109 BEA_WLS_SAMPLE_ADK - admin opened connection to EIS 

In the pattern,

The text after the "-" is the message of the statement.

Putting the Components Together

Listing 5-2 declares a new category for the sample adapter, sets its priority, and declares an appender to output log messages to a file:

Listing 5-2 Sample XML Code for Declaring a New Log Category

<!-
IMPORTANT!!! ROOT Category for the adapter; making this unique prevents other adapters from logging to your category 
--> 
<category name='BEA_WLS_SAMPLE_ADK' class='com.bea.logging. LogCategory'> 
  <!-
    Default Priority Level; may be changed at runtime  
    DEBUG means log all messages from the adapter's code base  
    INFO means log informationals, warnings, errors, and audits  
    WARN means log warnings, errors, and audits  
    ERROR means log errors and audits  
    AUDIT means log audits only  
  --> 
  <priority value='DEBUG' class='com.bea.logging.LogPriority'/> 
  <!-- 
   Associate one or more output destinations with this 
   category; in this case, the appender is set in an <appender> 
   element called 'FileAppender'
  -->  
  <appender-ref ref='FileAppender'/>
</category>

Note: You must specify the class as com.bea.logging.LogCategory.

 


How to Set Up Logging

Note: The following procedure assumes that you've cloned a development environment by running the GenerateAdapterTemplate utility. For more information on this utility, see Creating a Custom Development Environment.

Setting up the logging framework for your adapter is a four-step process.

  1. Identify all of the basic components used in the adapter. For example, if your adapter has an EventGenerator, you might want to have an EventGenerator component; if it supports a design-time GUI, you will need a design-time component.

  2. Open the base log configuration file from the cloned adapter. This file is found in <WLAI_HOME>/dev/<CLONE>/src/ and will have the extension .xml. For example, the DBMS adapter configuration file is in <WLAI_HOME>/dev/dbms/src. It's called BEA_WLS_DBMS_ADK.xml.

  3. In the base log configuration file, add the category elements for all adapter components you identified. For each category element, establish a priority. Listing 5-3 shows how a category for an EventGenerator with a priority of DEBUG is added.

    Listing 5-3 Sample Code Adding an EventGenerator Log Category with a Priority of DEBUG

      <category name='BEA_WLS_DBMS_ADK.EventGenerator'
                class='com.bea.logging.LogCategory'>
        <priority value='DEBUG'
                  class='com.bea.logging.LogPriority'/>
      </category>

  4. Determine the appender and add it to the configuration file. If necessary, add message formatting information. Listing 5-4 shows how a basic file appender is added within the <appender> element. Instructions within the <layout> element identify the message format pattern.

    Listing 5-4 Sample Code Adding a File Appender and Layout Pattern

    <!-- A basic file appender -->
    <appender name='FileAppender' class='org.apache.Log4j.FileAppender'>
        <!-- Send output to a file -->
        <param name='File' value='BEA_WLS_DBMS_ADK.log'/>
        <!-- Truncate existing -->
        <param name="Append" value="true"/>
        <!-- Use a basic LOG4J pattern layout -->
        <layout class='org.apache.Log4j.PatternLayout'>
          <param name='ConversionPattern' value='%-5p %d{DATE} %c{4} %x - %m%n'/>
        </layout>		
    </appender>

At this point, you should review these other configuration files to confirm their settings.

 


Logging Framework Classes

In addition to understanding the basic concepts of the logging framework, you will also need to understand three main classes provided in the log toolkit:

com.bea.logging.ILogger

This is the main interface to the logging framework. It provides numerous convenience methods for logging messages.

In How to Set Up Logging, you saw how you can configure logging in the base log configuration file. You can also configure logging programmatically by implementing the logging methods listed below:

com.bea.logging.LogContext

This class encapsulates information needed to identify an ILogger instance in the logging framework. Currently, a LogContext encapsulates a log category name and a locale, such as en_US.

com.bea.logging.LogManager

This class provides a method to allow you to configure the logging framework and provides access to ILogger instances.

To properly configure the log toolkit for your adapter, the ADK implements the LogManager's configure() method with the arguments shown in Listing 5-5:

Listing 5-5 Sample Code for Configuring the Log Toolkit

public static LogContext 
  configure(String strLogConfigFile, 
            String strRootLogContext, 
            String strMessageBundleBase,
            Locale locale,
            ClassLoader classLoader)

Table 5-2 describes the arguments passed by configure():

Table 5-2


 

Argument

Description

strLogConfigFile

This file contains the log configuration information for your adapter. The file should exist on the classpath. We recommend that you include this file into your adapter's main .jar file so that it can be included in the .war and .rar files for your adapter. This file should conform to the Log4j.dtd. The Log4j.dtd file is provided in the Log4j.jar in the Application Integration distribution.

strRootLogContext

This is the name of the logical root of the category hierarchy for your adapter. For the sample adapter, this value is BEA_WLS_SAMPLE_ADK.

strMessageBundleBase

This is the base name for the message bundles for your adapter. It is required by the ADK that you use message bundles. For the sample adapter, this value is BEA_WLS_SAMPLE_ADK.

locale

This identifies the locale (language and nation). The log toolkit organizes categories into different hierarchies based on locale. For example, if your adapter supports two locales en_US and fr_CA, the log toolkit will maintain two category hierarchies, one for en_US and one for fr_CA.

classLoader

This is the ClassLoader the LogManager should use to load resources, such as ResourceBundles and log configuration files.

Once the configuration is complete, you can retrieve ILogger instances for your adapter by supplying a LogContext object:

Listing 5-6 Sample Code for Supplying a LogContext Object

LogContext logContext = new LogContext("BEA_WLS_SAMPLE_ADK", java.util.Locale.US); 
ILogger logger = LogManager.getLogger(logContext); 
logger.debug("I'm logging now!"); 

The ADK hides most of the log configuration and setup for you. The com.bea.adapter.spi.AbstractManagedConnectionFactory class configures the log toolkit for service adapters and the AbstractEventGenerator configures the log toolkit for event adapters. In addition, all of the CCI and SPI base classes provided in the ADK provide access to an ILogger and its associated LogContext.

For other layers in the adapter to access the correct ILogger object, there are two approaches you can take.

Note: "Other layers" refers to layers in an adapter that support the CCI/SPI layer, such as a socket layer for establishing communication to the EIS.

 


Internationalization and Localization of Log Messages

Internationalization and Localization are central concepts to the ADK logging framework. All logging convenience methods on the ILogger interface, except the debug methods, allow internationalization. The implementation follows the Java Internationalization standards, using ResourceBundle objects to store locale-specific messages or templates. Sun provides a good online tutorial on using the I18N ("internationalization") and L10N ("localization") standards of the Java language.

 


Saving Contextual Information in a Multi-Threaded Component

Most real-world systems have to deal with multiple clients simultaneously. In a typical multi-threaded implementation of such a system, different threads will handle different clients. Logging is especially well suited to trace and debug complex distributed applications. A common approach to differentiate the logging output of one client from another is to instantiate a new separate category for each client. This promotes the proliferation of categories and increases the management overhead of logging.

A lighter technique is to uniquely stamp each log request initiated from the same client interaction. Neil Harrison described this method in "Patterns for Logging Diagnostic Messages," in Pattern Languages of Program Design 3, edited by R. Martin, D. Riehle, and F. Buschmann (Addison-Wesley, 1997).

To uniquely stamp each request, the user pushes contextual information into the Nested Diagnostic Context (NDC). The log toolkit provides a separate interface for accessing NDC methods. The interface is retrieved from the ILogger by using the method getNDCInterface().

NDC printing is turned on in the XML configuration file (with the symbol %x). Every time a log request is made, the appropriate logging framework component includes the entire NDC stack for the current thread in the log output. The user will not need to intervene in this process. In fact, the user is responsible only for placing the correct information in the NDC by using the push and pop methods at a few well-defined points in the code.

Listing 5-7 Sample Code

public void someAdapterMethod(String aClient) {
  ILogger logger = getLogger();
  INestedDiagnosticContext ndc = logger.getNDCInterface();
  // I'm keeping track of this client name for all log messages
  ndc.push("User name=" + aClient);
  // method body 
  ndc.pop();
}

A good place to use the NDC is in your adapter's CCI Interaction object.

 

back to top previous page next page