Diagnostics is a feature introduced in JCL 1.1 as an aid to debugging problems
with JCL configurations. When diagnostics are switched on, messages are logged
to a stream (specified by the user) by the two main class involved in discovery
JCL (LogFactory and LogFactoryImpl).
Diagnostics are intended to be used in conjunction with the source. The source contains numerous and lengthy comments. Often these are intended to help explain the meaning of the messages.
Diagnostic logging is intended only to be used when debugging a problematic configuration. It should be switched off for production.
Diagnostic logging is controlled through the system property
org.apache.commons.logging.diagnostics.dest. Setting the property value
to the special strings STDOUT or STDERR (case-sensitive)
will output messages to System.out and System.err respectively.
Setting the property value to a valid file name will result in the messages being logged
to that file.
Diagnostics uses the concept of an Object ID (OID). This allows the identity of objects
to be tracked without relying on useful toString implementations.
These are of the form:
classname@system identity hash code
The system identity hash code is found by calling System.identityHashCode()
which should uniquely identify a particular instance. The classname is usually the fully qualified
class name though in a few cases, org.apache.commons.logging.impl.LogFactoryImpl may be
shorten to LogFactoryImpl to increase ease of reading. For example:
sun.misc.Launcher$AppClassLoader@20120943
LogFactoryImpl@1671711
OIDs are intended to be used to cross-reference. They allow particular instances of classloaders and JCL classes to be tracked in different context's. This plays a vital role in building up the understanding of the classloader environment required to diagnose JCL problems.
Each diagnostic message is prefixed with details of the class being logger in a standard format. This takes the form:
[class-identifier -> ClassLoader OID]
ClassLoader OID is the OID of a classloader which loaded the class issuing the message. class-identifier identifies the object issuing the message.
In the case of
LogFactory, this is just LogFactory. For example (line split):
[LogFactory
-> sun.misc.Launcher$AppClassLoader@20120943] BOOTSTRAP COMPLETED
In the case of
LogFactoryImpl, the prefix is the instance OID. This can be cross referenced
to discover the details of the TCCL used to manage this instance. For example (line split):
[LogFactoryImpl@1671711
-> sun.misc.Launcher$AppClassLoader@20120943] Instance created.
Understanding the relationships between classloaders is vital when debugging JCL.
At various points, JCL will print to the diagnostic log the hierarchy for important
classloaders. This is obtained by walking the tree using getParent.
Each classloader is represented (visually) by an OID (to allow cross referencing)
and the relationship indicated in child --> parent fashion.
For example (line split for easy reading):
ClassLoader tree:java.net.URLClassLoader@3526198
--> sun.misc.Launcher$AppClassLoader@20120943 (SYSTEM)
--> sun.misc.Launcher$ExtClassLoader@11126876
--> BOOT
Represents a hierarchy with four elements ending in the boot classloader.
Whenever the LogFactory class is initialized, diagnostic messages about
the classloader environment are logged. The content of each of these messages is prefixed by
[ENV] to help distinguish them. The extension directories, application classpath,
details of the classloader (including the OID and toString
value) used to load LogFactory and the
classloader tree for that classloader
are logged.
Many Sun classloaders have confusing toString values. For example, the OID may be
sun.misc.Launcher$AppClassLoader@20120943
with a toString value of
sun.misc.Launcher$AppClassLoader@133056f
Other classloader implementations may give very useful information (such as the local classpath).
Finally, once initialization is complete a BOOTSTRAP COMPLETED message is issued.
LogFactoryImpl is the standard and default LogFactory implementation.
This section obviously only applies to configurations using this implementation.
Before assigning a Log instance, LogFactory loads a
LogFactory implementation. The content is prefixed by [LOOKUP]
for each diagnostic message logged by this process.
The implementation used can vary per Thread context classloader (TCCL). If this the first time that a Log has been requested for a particular TCCL a new instance will be created.
Information of particular interest is logged at this stage. Details of the TCCL are logging
allowing the OID later to be cross-referenced to the toString value
and the classloader tree. For example, the
following log snippet details the TCCL (lines split):
[LogFactory -> sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] LogFactory implementation requested for the first time for context
classloader java.net.URLClassLoader@3526198
[LogFactory -> sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] java.net.URLClassLoader@3526198 == 'java.net.URLClassLoader@35ce36'
[LogFactory -> sun.misc.Launcher$AppClassLoader@20120943]
[LOOKUP] ClassLoader tree:java.net.URLClassLoader@3526198
--> sun.misc.Launcher$AppClassLoader@20120943 (SYSTEM)
--> sun.misc.Launcher$ExtClassLoader@11126876
--> BOOT
The standard LogFactoryImpl issues many diagnostic messages when discovering
the Log implementation to be used.
During discovery, environment variables are loaded and values set. This content is prefixed by
[ENV] to make it easier to distinguish this material.
The possible messages issued during discovery are numerous. To understand them, the source
should be consulted. Attention should be paid to the classloader hierarchy trees for the
classloader used to load LogFactory and to the TCCL.