Author: Ken Ebbs

The logging package contains classes and interfaces derived from JDK 1.4 logging that are used by all iAS components to log debug as well as error information.

# iAS Logging Reference Guide

Logging in iAS is based as closely as possible on JDK 1.4 logging. Since we share a large amount of code with the Reference Implementation, the goal here is to keep logging in the RI be aligned with JDK 1.4 and as closely as possible with early drafts of JSR117 logging specifications related to domains. This logging package has augmented or used JDK 1.4 logging as follows:

- IAS adds some new log levels
- Loggers are context aware so that logging on the server side (within the application) server behaves differently than in the Application Client container or in the logging tools.
- A number of predefined loggers are defined and are aligned around the subsystems of iAS (e.g. JMS, JTS, Orb, EJB, etc.).
- Log levels can be configured via the iAS Administrative GUI (persisted in the iAS configuration file server.xml). This allows log levels to be graphically and dynamically configured; although dynamic configuration may not happen in the iAS70 time frame.
- Logging guidelines indicate design patterns that should be followed when logging.
- Resource bundle naming conventions are adopted.

Logging is discussed in more detail in the iAS Logging Functional Specification. This document is intended to serve as a technical reference to the functional specification.

## 1.0 Overview

In general, entities wanting to log use the standard JDK 1.4 logging APIs. Here is an example...

  import java.util.logging.Logger;
  ...
  Logger logger = Logger.getLogger("javax.enterprise.core.transaction");
  logger.finer("This is a test");

Exceptional cases will be discussed below. Anyone implementing logging should read this document, summary information can be found in the Guidelines and Summary sections of this document

## 2.0 Log Levels

In addition to the standard JDK levels, IAS has added additional levels designed to map more intuitively to Syslog to integrate more cleanly with Solaris. The IASLevel class exists for this purpose and is derived from java.util.logger.Level. It defines the following log levels.

Level Name | Integer Value | Description
Level.FINEST | 300 | All of FINE, FINER, and FINEST are intended for relatively detailed tracing. The exact meaning of the three levels will vary between subsystems, but in general, FINEST should be used for the most voluminous detailed output, FINER for somewhat less detailed output, and FINE for the lowest volume (and most important) messages. FINEST indicates a highly detailed tracing message.
Level.FINER | 400 | All of FINE, FINER, and FINEST are intended for relatively detailed tracing. The exact meaning of the three levels will vary between subsystems, but in general, FINEST should be used for the most voluminous detailed output, FINER for somewhat less detailed output, and FINE for the lowest volume (and most important) messages. FINER indicates a fairly detailed tracing message. By default logging calls for entering, returning, or throwing an exception are traced at this level.
Level.FINE | 500 | All of FINE, FINER, and FINEST are intended for relatively detailed tracing. The exact meaning of the three levels will vary between subsystems, but in general, FINEST should be used for the most voluminous detailed output, FINER for somewhat less detailed output, and FINE for the lowest volume (and most important) messages. In general the FINE level should be used for information that will be broadly interesting to developers who do not have a specialized interest in the specific subsystem. FINE messages might include things like minor (recoverable) failures. Issues indicating potential performance problems are also worth logging as FINE.
Level.CONFIG | 700 | CONFIG messages are intended to provide a variety of static configuration information, to assist in debugging problems that may be associated with particular configurations. For example, CONFIG message might include the CPU type, the graphics depth, the GUI look-and-feel, etc. We will not be using this in IAS.
Level.INFO | 800 | Typically INFO messages will be written to the console or its equivalent. So the INFO level should only be used for reasonably significant messages that will make sense to end users and system admins.
Level.WARNING | 900 | In general WARNING messages should describe events that will be of interest to end users or system managers, or which indicate potential problems.
Level.SEVERE | 1000 | In general SEVERE messages should describe events that are of considerable importance and which will prevent normal program execution. They should be reasonably intelligible to end users and to system administrators.
IASLevel.ALERT* | 1100 | A message that can be acted upon by a human intervention. Borrowed the idea from syslog() interface.
IASLevel.FATAL* | 1200 | Fatal error reporting after which server execution is not recommended. Hopefully, the last message before a server crash.

* indicates that this is not a standard log level

For portability reasons, convenience methods (e.g. Logger.alert() and Logger.fatal()) will not be provided for the extended levels, and the level constants must be used directly. Here is an example...

  import java.util.logging.Logger;
  import com.iplanet.ias.logging.IASLevel;
  ...
  Logger logger = Logger.getLogger("javax.enterprise.core.transaction");
  logger.log(IASLevel.FATAL, "server_startup.fatal_exception");

## 3.0 Accessing A Logger

One observation from the above code is that the logger name (e.g.. "javax.enterprise.core.transaction") will be embedded everywhere in the code. Some techniques will be used to limit the exposure to logger names. This is highly desirable as logger names may need to change (e.g. as JSR 117 evolves).

1. Logger names will be represented as constants defined in a class named com.sun.logging.LogDomains (a name agreed upon with the RI team.)
2. We will attempt to limit exposure to logger initialization through the use of static Logger instances or member variables of common classes.

In addition, loggers must be registered with the LogManager so that calls to Logger.getLogger() will return the appropriate logger. There are three basic approaches to this:

1. All loggers are registered before they are referenced (e.g. at application or application server startup time). The issue here is that each application who wishes to log must be "logger aware" and invoke appropriate initialization code.
2. All loggers are registered from within the standard logging.properties file. There is a debate about whether this is supported, but in any case, logging.properties is configured at the VM (JRE) level and when multiple iAS instances share the same VM, we would have to override its default location.
3. Each logger is registered upon demand the first time it is accessed. This is the most flexible scheme and the one that we have chosen; however it requires a wrapper class around Logger.getLogger(). We have decided to use LogDomains.getLogger() for this purpose. This may cause issues with the 1.4 RI, but the problem can be rectified by a single global replacement.

Here is an example that sums it all up.
  import java.util.logging.Logger;
  import com.sun.logging.LogDomains;
  public class foo {
  private static _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
  public void bar() {
  _logger.fine("Begin transaction");
  }
  }

## 4.0 Resource Bundles

The ability to localize certain log message is critical and JDK 1.4 defines a mechanism by which a resource bundle file name can be associated with a logger. IAS will use this mechanism and defines a naming convention for the resource bundles. Here are the guidelines that will be followed for localization of log messages.

1. Each logger will have its own resource bundle.
2. The resource bundle associated with the logger will be <loggerName>.LogStrings.properties. One exception is that since the logger names are rooted at javax according to JSR 117, the resouce bundle will be packaged according to com.sunlogging. For example the resource bundle for javax.enterprise.resource.corba will be com.sun.logging.enterprise.resource.corba.LogStrings.properties. This implies that property files will be packaged in a directory structure corresponding to the loggers name. The name LogStrings.properties will be used to differentiate log messages from other localized messages (e.g. stored in LocalStrings.properties). It should be noted that this is a general rule to follow, but the framework will not impose this so that arbitrary resource bundles can be used if necessary.
3. There is no convention around the use of keys in the LogStrings.properties resource bundles, except that the keys should convey the meaning of the log message to improve code readability. See Message Ids.
4. Each string in LogStrings.properties should be of the form <messageId>: <message text>. See Message Ids.
5. The resource bundle (LogStrings.properties) should only be used for logging messages and not mixed with other localized string (e.g. to be displayed in GUI or CLI). The reason for this is that log messages need unique message ids (discussed below) and we do not want to pollute the message id space.
6. Messages whose level is INFO or greater must be localized. Debug messages (CONFIG, FINE, FINER, and FINEST) need not be localized.

One ramification of this decision is that the LocalStringManager implementation used by the RI (which walks up the classes hierarchy to find a ResourceBundle containing the given key) will not work unless special purpose formatters are inserted. This method of fetching localized strings is not compatible out of the box with standard JDK 1.4 logging. Tomcat employs a similar naming convention but does not attempt to climb the hierarchy. This can be used directly by JDK 1.4 logging.

### 4.1 Message Ids

One requirement is that logged messages have a unique message id. The message id is of the form <Subsystem><4CharacterIntegerId> where the <4CharacterIntegerId> need only be unique within the subsystem. Examples are "JMS0001", "JTS0001". These error messages will then be documented (e.g. with a cause, meaning, and action to take) in an administrators guide.

The resource bundle keys used in the existing resource bundles (e.g. LocalStrings.properties) used in the RI and in Tomcat currently are not suitable as message ids and follow no real convention other than they attempt to convey the cause of the error e.g. "enterprise.deployment.invalid_format". IAS will follow the same rule. In the RI, LocalStrings.properties (and the LocalStringManager) are used mostly for throwing exceptions whose text is localized and in some cases to display (i.e. log) localized messages. In Tomcat LocalStrings.properties (and the StringManager) is used extensively for logging localized messages and for logging messages.

MessageIds in IAS will be embedded in each of the strings found in LogStrings.properties. The format of these strings will be <messageId>:<messageText>. Here are some examples:

  deploy_tool.file_not_found="TLS0023: File {0} not found during deployment"
  deploy_tool.insufficient_privilege="TLS0025: User {0} does not have privilege to perform the operation"

Embedding messageIds within the strings is a convention adopted by IAS. Other groups using JDK logging can choose whether or not to adopt this convention.

### 4.2 Throwing And Logging Exceptions

Often times an exception is thrown that contains text indicating the cause of the exception. For example,
  throw new IllegalStateException("Operation not allowed");

After looking through existing code, in some cases this string is localizable via a Resource Bundle, and in other cases it is not. It is unrealistic to expect that all exception text will be localizable. Therefore any existing mechanisms to localize exception text will not be changed.

Exceptions will be used using the Logger.log(Level level, String msg, Throwable thrown) message. If the Level if INFO or greater, the msg must refer to a localized message defined in LogStrings.properties. Here is an example:

  catch (Exception ex) {
  _logger.log(Level.WARNING, "j2eerunner.startup_failed", ex);
  }

## 5.0 Predefined Loggers

JDK 1.4 logging suggests that logger names mirror the application's package structure. In addition, the logger namespace is hierarchical. For example, if a logger named "javax.enterprise" is registered and the user requests via Logger.getLogger() a logger named "javax.enterprise.core.transaction" (which has not been registered), then the logger for "javax.enterprise" will be returned. IAS will adopt this naming standard and may make use of the hierarchical capability of JDK 1.4 logging.

The IAS runtime defines a number of subsystems. The properties for these subsystems is configurable in server.xml in particular, one of the properties (log-level) indicates the enabled log level for a particular subsystem. The IAS administrative GUI can then set subsystem specific log levels. For this to function, each subsystem must have its own logger. The subsystems and their logger name is given in the table below.

Another issue is that JSR117 defines a concept called logging domains. This is in its very early stages, but it attempts to give a well defined hierarchy of loggers and define explicitely what is logged by each. The hierarchy closely matches the J2EE managed object hierarchy defined in JSR 77. The logger names listed below match this hierarchy as closely as possible. The ramification of this decision is that the logger name does not match the existing package hierarchy. Also note that the resource bundles should not be packaged in javax and hence will be packaged in com.sun instead. Again, since these names are constant, developers should be isolated from the changes.

The latest version of JSR 117 Logging has more details about the hierarchy. Developers are encouraged to add finer grained loggers that comply with the naming listed in JSR 117. See Adding A New Logger for more details. This will allow further partitioning of resource bundles and closer adherence to JSR 117. For example a javax.enterprise.system.tools.deployment logger (and associated resource bundle) could be added for logging related to the deployment backend. It would by default inherit its log level from javax.enterprise.system.tools defined in server.xml; however, the default level could be overridden using the standard logging.properties file. Another example is that the logger for java mail should be javax.enterprise.resource.javamail.

Subsystem Description | Subsystem Id | LogDomains Constant | Logger Name | Resource Bundle Name | entry in server.xm;l
The admin server | ADMN | TOOLS_LOGGER | javax.enterprise.system.tools | com.sun.logging.enterprise.system.tools.LogStrings | <admin-service>
The EJB container | EJB | EJB_LOGGER | javax.enterprise.system.container.ejb | com.sun.logging.enterprise.system.container.ejb.LogStrings | <ejb-container>
Java Mail | JML | JAVAMAIL_LOGGER | javax.enterprise.resource.javamail | com.sun.enterprise.resource.javamail.LogStrings | <log-service> properties*
The Web container (comcat) | WEB | WEB_LOGGER | javax.enterprise.system.container.web | com.sun.logging.enterprise.system.container.web.LogStrings | <web-container>
The MDB (Message Driven) Bean container | MDB | MDB_LOGGER | javax.enterprise.system.container.ejb.mdb | com.sun.logging.enterprise.system.container.ejb.mdb.LogStrings | <mdb-container>
The JMS (iMQ) service | JMS | JMS_LOGGER | javax.enterprise.resource.jms | com.sun.logging.enterprise.resource.jms.LogStrings | <jms-service>
The security service | SEC | SECURITY_LOGGER | javax.enterprise.system.core.security | com.sun.logging.enterprise.system.core.security.LogStrings. | <security-service>
The JTS (transaction) service | JTS | TRANSACTION_LOGGER | javax.enterprise.system.core.transaction | com.sun.logging.enterprise.system.core.transaction.LogStrings | <transaction-service>
The ORB | ORB | CORBA_LOGGER | javax.enterprise.resource.corba | com.sun.logging.enterprise.resource.corba.LogStrings | <iiop-service>
Default handlers. For all entries that are not associated with a particular subsystem (e.g. utility classes) there will be a default logger. | UTIL, LCM | ROOT_LOGGER | javax.enterprise | com.sun.logging.enterprise.LogStrings | <log-service>
Application Client Container | ACC | ACC_LOGGER | javax.enterprise.system.container.appclient | com.sun.logging.enterprise.system.container.applclient.LogStrings | <log-service> properties*
| UTIL | UTIL_LOGGER | javax.enterprise.system.util | com.sun.logging.enterprise.system.util.LogStrings.properties |
JNDI and naming | NAM, JNDI | NAMING_LOGGER | javax.enterprise.system.core.naming | com.sun.logging.enterprise.system.core.naming.LogStrings.properties |
Verifier tool | APP | APPVERIFY_LOGGER | javax.enterprise.system.tools.verifier | com.sun.logging.enterprise.system.tools.verifier.LogStrings.properties |
Activation | ACT | ACTIVATION_LOGGER | javax.enterprise.system.activation | com.sun.logging.enterprise.system.activation.LogStrings.properties |
JTA | DTX | JTA_LOGGER | javax.enterprise.resource.jta | com.sun.logging.enterprise.resource.jta.LogStrings.properties |
Resource Adaper | RSR | RSR_LOGGER | javax.enterprise.resource.resourceadapter | com.sun.logging.enterprise.resource.resourceadapter.LogStrings.properties |
Deployment | DPL | DPL_LOGGER | javax.enterprise.system.tools.deployment | com.sun.logging.enterprise.system.tools.deployment.LogStrings.properties |
Admin Backend | ADM | ADMIN_LOGGER | javax.enterprise.system.tools.admin | com.sun.logging.enterprise.system.tools.admin.LogStrings.properties |
| SERVER | SERVER_LOGGER | javax.enterprise.system | com.sun.logging.enterprise.system.LogStrings.properties |
| CORE | CORE_LOGGER | javax.enterprise.system.core | com.sun.logging.enterprise.system.core.LogStrings.properties |
Classloader | LOADER | LOADER_LOGGER | javax.enterprise.system.core.classloading | com.sun.logging.enterprise.system.core.classloading.LogStrings.properties |
Admin Backend Configuration | CONF | CONFIG_LOGGER | javax.enterprise.system.core.config | com.sun.logging.enterprise.system.core.config.LogStrings.properties |
|  | There are also a number of loggers used by our cmp code which are not assigned names in LogStrings.properties |  |  |

*Loggers that are not defined at log-level attributes of an entry in server.xml can be defined via log-service properties. In this case the name of the property is the logger name, and the value is the property value.

In addition configuration of both the application server and the Application client container contain a log service element consisting of the following elements:

Log Service Attribute | Description
file | The file to which logging will be redirected
level | The default level for all loggers not specified in the above table

## 6.0 Adding A New Logger

As stated earlier, developers are encouraged to add new loggers is a relatively straight forward task that involves the following:

1. Use JSR 117 Logging to determine the logger's name (e.g. javx.enterprise.resource.javamail).
2. Determine a Subystem id for the logger (or use the subsystem id of its parent).
3. Create the LogStrings.properties file in the corresponding logging directory (e.g. com.sun.logging.enterprise.resource.javamail.LogStrings.properties). Note that this packaging corresponds exactly to the logger's name (except that java is replace by com.sun.logging).
4. Add the constant name to LogDomains.java.
5. Update this document package.html and append to the previous table in section Predefined Loggers.

## 7.0 Server vs Client Side Logging

There is a distinction made between server side logging (i.e. done within the runtime of the application server and its subsystems) and client side logging (i.e. logged from within the Application client container). This is transparent from the caller's point of view, as the caller uses the standard JDK 1.4 logging APIs. At logger initialization time, the appropriate logger (either client or server side) will be registered. Both result in logging to a file. In the case of the server, the web core's native ereport logging infrastructure is used allowing messages logged by the web-core (in C++) to be co-mingled with the application server's log messages. This is not suitable for the Application client container as the runtime support for ereport does not exist. On the client side a more standard java.util.logging.FileLogger will be used.

## 8.0 Logging Conventions And Guidelines

Here are some conventions and guidelines that should be followed.

1. Level.CONFIG should not be used. Use INFO instead. (This is an IAS specific rule.)
2. When logging exceptions

1. Exceptions should be propagated up and logged at the outermost level only. This will avoid duplicate log messages for a single exception
2. Exceptions should be logged using Logger.log(Level, String message, Throwable). If the exception being logged is of type INFO or higher, the message passed in should refer to resource bundle id (hence localizable).
3. Never eat exceptions (without a least logging a FINEST message).
4. The JDK 1.4 exception chaining facility should be used when catching an exception and rethrowing it as another exception. This will ensure that proper stack trace information is maintained.

3. With respect to Resource bundles

1. Each logger will have its own resource bundle named <logger name>.LogStrings.properties
2. Debug (i.e. CONFIG, FINE, FINER, FINEST) messages need not be localizable
3. Do not mix resource bundles used for logging (LogStrings.properties) with resource bundles used for other (e.g. GUI) localized strings
4. Resource bundle strings will contain message ids of the form <subsystem><integerId>.

4. Expensive calls to log should be guarded with a level check using Logger.isLoggable(Level). The first thing a logger does is a level check for performance reasons, but in many cases it may be expensive to evaluate the arguments passed to the log function (e.g. they may contain method calls, string concatenation, etc.) Here is an example....
  if (_logger.isLoggable(Level.FINE)) {
  _logger.fine(foo() + " is " + bar() + " then " + baz());
  }
5. Anything logged as INFO or greater must be localized (i.e. it must have an entry in LogStrings.properties with a valid message id).
6. Any exception logged as a WARNING, SEVERE or higher should include a stack trace.
7. Any exception that was previously logged using ex.printStackTrace() should be logged as a level of WARNING or SEVERE.
8. If you are catching an exception and re-throwing a new exception that does not chain the original exception, you should log a FINE message (including the stack trace of the original exception) prior to throwing the new exception.
9. If you are catching an exception and re-throwing a new exception that chains the original exception, you should log a FINER message (including the stack trace of the original exception) prior to throwing the new exception.
10. If you are logging an exception that was previously eaten (with no logging), then you should log a FINER messsage (including the stack trace of the original exception). NOTE: if it is clear that the authors intent was to eat the exception (e.g. due to a comment in the code) then there should be no logging. This only applies to cases where it is questionable whether the exception should be eaten.

## 9.0 Summary

Let's assume we are using the logger for javax.enterprise.resource.jms. This logger name can be accessed through the constant string com.sun.logging.LogDomains.JMS_LOGGER. The resource bundle associated with this logger can be found in com.sun.logging.enterprise.resource.jms.LogStrings.properties.

Here is an example that can be found in LogStrings.properties. Note the message id embedded in the message string.

  event_processor.topic_not_found="JMS0010: Topic does not exist"
  event_processor.file_not_found="JMS0011: File {0} not found"

And now here is some example logging code....

  import java.util.logging.Logger;
  import java.util.logging.Level;
  import com.sun.logging.LogDomains;
  public class foo {
  //Loggers are declared statically to limit their initialization.
  //We could use Logger.getLogger() in this case to be completely JDK standard. The ramification is that
  //the named logger would have to be registered with the LogManager.
  private static _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
  public void function(String fileName) {
  //Debug messages need not be localized
  _logger.fine("Entering function at with file " + fileName);
  ...
  _logger.warning("event_processor.topic_not_found");
  ...
  _logger.log(Level.WARNING, "event_processor.file_not_found", fileName);
  }
  }

## 10.0 Retrofitting Existing Logging

This section provides some guidelines for retrofitting existing logging mechanisms in the RI and Tomcat to make them as compatible as possible with the logging guidelines stated above.

### 10.1 Logging In The RI

Formal logging in the RI code (i.e. roughly anything in src/java/com/sun) is non-existant. Instead there are a variety of mechanisms which eventually write to stdout and stderr. In the original (i.e. not modified by IAS) RI code, there were mechanisms including redirection of stdout and stderr that caused log files to be created in logs/<hostname>/j2ee/j2ee, etc. These mechanisms have been removed in IAS so the end result is that all output should go to stdout and stderr. Currently in the server (i.e. but not in the Application Client Container for example) anything written to stdout is redirected to the web core's log file (i.e. logs/errors) via eReport (the web core's native logging infrastructure). Output to stdout has severity level INFO and stderr level WARNING. So really, the task that must be done in the RI is to replace anything that writes to stdout/stderr with JDK logging. The hardest thing about this task will be to get the context of where to logging occurs. This is due to the fact that there are many files checked into the RI which are not used in iAS. When in doubt we can go ahead and make the change.

When logging in a subsystem for which a logger is not defined, be sure to consult the domains laid out in JSR 117 and if possible create a new logger rather than using ROOT_LOGGER. For example javax.enterprise.resource.javamail should be used. See Adding A New Logger for details.

Now here is a list of some of the things to look for....

1. System.out and System.err
2. Log.err and Log.out in com.sun.enterprise.log are utilities which log to stdout and stderr
3. ex.printStackTrace() will log a stack trace
4. com.sun.corba.ee.internal.CosNaming.NamingUtils.dprint()
5. com.sun.ejb.containers.util.pool.PoolException.printStackTrace()
6. com.sun.enterprise.resource.PoolingException.printStackTrace()
7. com.sun.enterprise.resource.IASPoolManagerDebug;
8. com.sun.enterprise.server.J2EEServer.ostream and estream

Also be aware that most of the output in the RI code will be considered a debug message (FINE, FINER, FINEST). The exception is that logging of exceptions will probably have a higher severity level (WARNING, SEVERE, FATAL). When in doubt, it is safer to be more verbose than less verbose as it is always easier to remove extraneous messages from the log after the fact.

The following table gives specifics about these occurrences.

| modules
Parent search string | Specific search string | Corba | Activation | EJB | Enterprise | Jms | Jndi
print | print() |  |  | 26 / 2 | 66 / 17 |  |
System.err.println |  |  | 58 / 15 | 149 / 45 |  |
System.out.println | 217 / 36 | 36 / 5 | 69 / 21 | 771 / 149 |  | 5 / 2
printDebug | 19 / 1 |  |  |  |  |
dprint | 272 /39 |  |  |  |  |
printStackTrace |  |  | 81 / 28 | 395 / 123 |  | 1 / 1
Log.err.println |  |  | 88 / 22 | 111 / 28 |  |
debug.println |  |  |  | 81 / 4 |  |
NamingUtils.errprint | 13 / 3 |  |  |  |  |
TraceUtil.print |  |  |  |  |  |
debug | debug.log | 47 / 1 |  |  |  |  |
debugPrintMessage | 9 / 2 |  |  |  |  |
debugPrintThrowable | 29 / 2 |  |  |  |  |
debug() |  |  |  | 51 / 8 |  |
Verifier.debug |  |  |  | 190 / 6 |  |
debugMessage |  |  |  |  |  |
trace | trace | 3 |  |  |  |  |
log | logTerminal | 10 / 1 |  |  |  |  |
logError | 5 / 1 |  |  |  |  |
logInformation | 7 / 1 |  |  |  |  |
Verifier.log |  |  |  | 10 / 2 |  |
| modules
Parent search string | Specific search string | jts | logging | mail | org | tools | web
print | print() | 7 |  |  |  |  |
System.err.println | 15 / 6 |  |  |  | 14 / 6 | 6 / 4
System.out.println | 17 / 4 |  | 90 / 8 |  | 26 / 6 | 32 / 6
printDebug |  |  |  |  |  |
dprint |  |  |  |  |  |
printStackTrace | 24 / 12 |  | 11 / 4 |  |  | 18 / 6
Log.err.println |  |  |  |  |  | 1 / 1
debug.println |  |  |  |  |  |
NamingUtils.errprint |  |  |  |  |  |
TraceUtil.print | 68 / 14 |  |  |  |  |
debug | debug.log |  |  |  |  |  |
debugPrintMessage |  |  |  |  |  |
debugPrintThrowable |  |  |  |  |  |
debug() |  |  |  |  |  |
Verifier.debug |  |  |  |  |  |
debugMessage | 9 / 1 |  |  |  |  |
trace | trace |  |  |  |  |  |
log | logTerminal |  |  |  |  |  |
logError |  |  |  |  |  |
logInformation |  |  |  |  |  |
Verifier.log |  |  |  |  |  |

The numbers in the cells denote the (number of occurences) / (number of files containing these occurences).

Empty cells denote zero occurences.
Here is some guidance provided by Deepak. Please use your best judgement and do not this for the letter of the law. For example, the table below applies a lot of INFO messages e.g. for tracing which in my mind would be better suited as FINE messages. INFO is not for debugging purposes. Also be careful about FATAL messages as these are intended to be errors from which the server cannot recover. Follow the guidelines in the Log Levels discussion.

Parent search string | Specific search string | Notes
print | print() | Debug and info messages.
System.err.println | Definitely important messages, most will fall under WARNING, ALERT, SEVERE,, and FATAL too.
System.out.println | About 25% is commented out, most of them are debug messages (FINE, FINER, FINEST). There are a few warnings, errors and fatal messages too.
printDebug | FINE and FINER messages.
dprint | A lot of INFO messages, some FATAL ones too.
printStackTrace | WARNING, SEVERE and a few FATAL messages.
Log.err.println | Most of the messages are WARN, SEVERE and FATAL.
debug.println | All are debug messages.
NamingUtils.errprint | WARNING messages.
TraceUtil.print | A lot of NFO messages.
debug | debug.log | All commented out …. they are all debug messages.
debugPrintMessage | All debug messages.
debugPrintThrowable | SEVERE and FATAL messages.
debug() | Mostly SEVERE, some are INFO.
Verifier.debug | Most are WARN and SEVERE, some debug.
debugMessage | All are debug messages.
trace | trace | INFO
log | logTerminal | All FATAL messages.
logError | SEVERE messages.
logInformation | INFO.
Verifier.log | debug messages.

Many times calls to System.out/err are guarded by some sort of if (debug) condition. In some cases debug is a static declared as false so in theory this code can never get executed w/o recompiling. We will make the rule that all of these debug statements will be replaced. Even commented out debug statements should be replaced.

The RI uses LocalStrings.properties (and potentially some other uniquely named property files) largely to place a localized message as the Exceptions text before throwing the exception. This code will remain unchanged. However, we will still need to walk through the messages in LocalStrings.properties and ensure that each and every message is referenced and used appropriately.

Finally note that some subsystems (e.g. JTS) have their own custom tracing and debugging facilities. These must be replaced with JDK logging.

To avoid conflict with newly inserted logging messages, start numbering at 5000.

### 10.2 Logging in Tomcat

Tomcat logging will evolve in the future toward jakarta logging which acts as a wrapper on top of log4j or JDK 1.4 logging. In any case the goal here is to intrude minimally on the code as it is likely to change in the future. Logging in Tomcat is done via the Logger interface defined in org.apache.jasper.logging and in org.apache.catalina. The implementation of the logger is easily pluggable and indeed iAS has already defined an implementation of this interface in com.iplanet.ias.web.logger.IASLogger.

The interesting methods in this interface are:

  public void log(String msg) // defaults to INFO and FINE for IAS
  public void log(Exception exception, String msg) // defaults to INFO and WARNING for IAS???
  public void log(String msg, Throwable throwable) // defaults to ERROR
  public void log(String message, int verbosity)
  public void log(String message, Throwable throwable, int verbosity)

The verbosity level is FATAL, ERROR, WARNING, INFORMATION, DEBUG and can easily be mapped to standard JDK logging levels. This implies that Tomcat Logger can be mapped easily to a JDK Logger call.

Here is the proposed mapping to JDK Levels. This can be accomplished in the IASLogger class:

Tomcat Level | JDK Level
DEBUG | FINE
INFORMATION | INFO
WARNING | WARNING
ERROR | SEVERE
FATAL | FATAL

Here are the main disconnects with the iAS logging strategy

1. Calls to log are already provided a localized String. This means that the resource bundle facility of JDK 1.4 logging will not be used and instead we will rely on the LocalStrings.properties files used within Tomcat. As with the RI, Tomcat uses LocalString.properties files mostly for throwing exceptions with localized text. There are a few occurrences of log calls that contain localized text, but the majority of log calls seem not to be localized.
2. In looking through the code it appears that most of the calls to log are of level INFO and do not contain localized text. For this reason, we have chosen to map INFO to JDK Level FINE.

In general it looks as if the levels and coverage in the code is adequate. The main task that must be done therefore is to assign message ids to the existing localized strings. Remember these localized strings are used sometimes in exception text and largely for throwing localized exceptions. There are 16 property files and 560 localized messages. The simplest approach would be to insert message ids into every one of these; however, this would violate the above rule stated for the RI that localized exception text should not contain message ids. In addition the ramification of so many message ids is that they have to be documented, etc. So ideally, we would assign message ids only to the relevant messages (i.e. those that are not part of exception text, but are used in logging). In addition, it is not clear whether many of these are used. My first pass approach would be to manually examine the files and make a call about assigning message ids.

The other approach is to be very detailed about this and examine every occurrence of Logger.log(). A quick search shows uses in the following places.

1. Logger.log() - about 1100 occurrences
2. Constants.message() -- 43 occurrences
3. WarpLogger() contains a bunch of wrappers and methods dump(), debug(), and log() which map to differing levels than those defined by the standard Logger.
4. StandardEngine().log
5. SaxContext().log
6. Some log calls (e.g. ProcessEnvironment().log) maps to System.out.println(). Not sure if this is OK
7. Logger.Helper

- The majority of calls to log are non-localized INFO messages (mapped to FINE in our case). These can be dismissed quickly. This is especially true of anything that is guarded by a debug level. log calls not guarded by a debug level (especially if they are localized) should be considered candidates for info level messages.
- Some log calls are localized INFO messages and we need do nothing with these.
- We need to examine exceptions logged to be sure severity is accurate. Note the subtle differences in the two method signatures:
  public void log(Exception exception, String msg) // defaults to INFO
  public void log(String msg, Throwable throwable) // defaults to ERROR
- Log calls whose level is INFO or greater must be localized