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).
-
Logger names will be represented as constants defined in a class named
com.sun.logging.LogDomains
(a name agreed upon with the RI team.)
-
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:
-
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.
-
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.
-
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.
-
Each logger will have its own resource bundle.
-
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.
-
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.
-
Each string in LogStrings.properties should be of the form <messageId>:
<message text>. See Message Ids.
-
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.
-
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:
-
Use JSR 117 Logging to determine the logger's name (e.g. javx.enterprise.resource.javamail).
-
Determine a Subystem id for the logger (or use the subsystem id of its
parent).
-
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).
-
Add the constant name to LogDomains.java.
-
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.
-
Level.CONFIG should not be used. Use INFO instead. (This is an IAS specific
rule.)
-
When logging exceptions
-
Exceptions should be propagated up and logged at the outermost level only.
This will avoid duplicate log messages for a single exception
-
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).
-
Never eat exceptions (without a least logging a FINEST message).
-
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.
-
With respect to Resource bundles
-
Each logger will have its own resource bundle named <logger name>.LogStrings.properties
-
Debug (i.e. CONFIG, FINE, FINER, FINEST) messages need not be localizable
-
Do not mix resource bundles used for logging (LogStrings.properties) with
resource bundles used for other (e.g. GUI) localized strings
-
Resource bundle strings will contain message ids of the form <subsystem><integerId>.
-
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());
-
}
-
Anything logged as INFO or greater must be localized (i.e. it must have
an entry in LogStrings.properties with a valid message id).
-
Any exception logged as a WARNING, SEVERE or higher should include a stack
trace.
-
Any exception that was previously logged using ex.printStackTrace() should
be logged as a level of WARNING or SEVERE.
-
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.
-
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.
-
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....
-
System.out and System.err
-
Log.err and Log.out in com.sun.enterprise.log are utilities which log to
stdout and stderr
-
ex.printStackTrace() will log a stack trace
-
com.sun.corba.ee.internal.CosNaming.NamingUtils.dprint()
-
com.sun.ejb.containers.util.pool.PoolException.printStackTrace()
-
com.sun.enterprise.resource.PoolingException.printStackTrace()
-
com.sun.enterprise.resource.IASPoolManagerDebug;
-
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
-
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.
-
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.
-
Logger.log() - about 1100 occurrences
-
Constants.message() -- 43 occurrences
-
WarpLogger() contains a bunch of wrappers and methods dump(), debug(),
and log() which map to differing levels than those defined by the standard
Logger.
-
StandardEngine().log
-
SaxContext().log
-
Some log calls (e.g. ProcessEnvironment().log) maps to System.out.println().
Not sure if this is OK
-
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