1
0

Added internal diagnostics

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@171301 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Simon Kitching
2005-05-22 10:43:52 +00:00
parent c485c20b1e
commit 110f2a234b

View File

@@ -76,6 +76,8 @@ public class LogFactoryImpl extends LogFactory {
*/ */
public LogFactoryImpl() { public LogFactoryImpl() {
super(); super();
initDiagnostics(); // method on this object
logDiagnostic("Instance created.");
} }
@@ -108,6 +110,11 @@ public class LogFactoryImpl extends LogFactory {
// ----------------------------------------------------- Instance Variables // ----------------------------------------------------- Instance Variables
/**
* The string prefixed to every message output by the logDiagnostic method.
*/
private String diagnosticPrefix;
/** /**
* Configuration attributes. * Configuration attributes.
*/ */
@@ -160,7 +167,6 @@ public class LogFactoryImpl extends LogFactory {
// --------------------------------------------------------- Public Methods // --------------------------------------------------------- Public Methods
/** /**
* Return the configuration attribute with the specified name (if any), * Return the configuration attribute with the specified name (if any),
* or <code>null</code> if there is no such attribute. * or <code>null</code> if there is no such attribute.
@@ -250,6 +256,7 @@ public class LogFactoryImpl extends LogFactory {
*/ */
public void release() { public void release() {
logDiagnostic("Releasing all known loggers");
instances.clear(); instances.clear();
} }
@@ -287,13 +294,90 @@ public class LogFactoryImpl extends LogFactory {
} }
// ------------------------------------------------------
// Static Methods
//
// These methods only defined as workarounds for a java 1.2 bug;
// theoretically none of these are needed.
// ------------------------------------------------------
/**
* Gets the context classloader.
* This method is a workaround for a java 1.2 compiler bug.
*/
protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
return LogFactory.getContextClassLoader();
}
/**
* Workaround for bug in Java1.2; in theory this method is not needed.
* See LogFactory.isInternalLoggingEnabled.
*/
protected static boolean isDiagnosticsEnabled() {
return LogFactory.isDiagnosticsEnabled();
}
/**
* Workaround for bug in Java1.2; in theory this method is not needed.
* See LogFactory.getClassLoader.
*/
protected static ClassLoader getClassLoader(Class clazz) {
return LogFactory.getClassLoader(clazz);
}
// ------------------------------------------------------ Protected Methods // ------------------------------------------------------ Protected Methods
/**
* Calculate and cache a string that uniquely identifies this instance,
* including which classloader the object was loaded from.
* <p>
* This string will later be prefixed to each "internal logging" message
* emitted, so that users can clearly see any unexpected behaviour.
* <p>
* Note that this method does not detect whether internal logging is
* enabled or not, nor where to output stuff if it is; that is all
* handled by the parent LogFactory class. This method just computes
* its own unique prefix for log messages.
*/
private void initDiagnostics() {
// It would be nice to include an identifier of the context classloader
// that this LogFactoryImpl object is responsible for. However that
// isn't possible as that information isn't available. It is possible
// to figure this out by looking at the logging from LogFactory to
// see the context & impl ids from when this object was instantiated,
// in order to link the impl id output as this object's prefix back to
// the context it is intended to manage.
Class clazz = this.getClass();
ClassLoader classLoader = getClassLoader(clazz);
diagnosticPrefix = clazz.getName() + "@" + classLoader.toString() + ":";
}
/**
* Output a diagnostic message to a user-specified destination (if the
* user has enabled diagnostic logging).
*
* @param msg
*/
protected void logDiagnostic(String msg) {
if (isDiagnosticsEnabled()) {
logRawDiagnostic(diagnosticPrefix + msg);
}
}
/** /**
* Return the fully qualified Java classname of the {@link Log} * Return the fully qualified Java classname of the {@link Log}
* implementation we will be using. * implementation we will be using.
* <p>
* This method looks in the following places:
* <ul>
* <li>Looks for an attribute LOG_PROPERTY or LOG_PROPERTY_OLD in the
* "attributes" associated with this class, as set earlier by method
* setAttribute.
* <li>Looks for a property LOG_PROPERTY or LOG_PROPERTY_OLD in the
* system properties.
* <li>Looks for log4j, jdk logging and jdk13lumberjack classes in
* the classpath.
* </ul>
*/ */
protected String getLogClassName() { protected String getLogClassName() {
@@ -302,14 +386,19 @@ public class LogFactoryImpl extends LogFactory {
return logClassName; return logClassName;
} }
logDiagnostic("Determining the name for the Log implementation.");
logDiagnostic("Trying to get log class from attribute " + LOG_PROPERTY);
logClassName = (String) getAttribute(LOG_PROPERTY); logClassName = (String) getAttribute(LOG_PROPERTY);
if (logClassName == null) { // @deprecated if (logClassName == null) { // @deprecated
logDiagnostic("Trying to get log class from attribute " + LOG_PROPERTY_OLD);
logClassName = (String) getAttribute(LOG_PROPERTY_OLD); logClassName = (String) getAttribute(LOG_PROPERTY_OLD);
} }
if (logClassName == null) { if (logClassName == null) {
try { try {
logDiagnostic("Trying to get log class from system property " + LOG_PROPERTY);
logClassName = System.getProperty(LOG_PROPERTY); logClassName = System.getProperty(LOG_PROPERTY);
} catch (SecurityException e) { } catch (SecurityException e) {
; ;
@@ -318,12 +407,15 @@ public class LogFactoryImpl extends LogFactory {
if (logClassName == null) { // @deprecated if (logClassName == null) { // @deprecated
try { try {
logDiagnostic("Trying to get log class from system property " + LOG_PROPERTY_OLD);
logClassName = System.getProperty(LOG_PROPERTY_OLD); logClassName = System.getProperty(LOG_PROPERTY_OLD);
} catch (SecurityException e) { } catch (SecurityException e) {
; ;
} }
} }
// no need for internalLog calls below; they are done inside the
// various isXXXAvailable methods.
if ((logClassName == null) && isLog4JAvailable()) { if ((logClassName == null) && isLog4JAvailable()) {
logClassName = "org.apache.commons.logging.impl.Log4JLogger"; logClassName = "org.apache.commons.logging.impl.Log4JLogger";
} }
@@ -340,6 +432,7 @@ public class LogFactoryImpl extends LogFactory {
logClassName = "org.apache.commons.logging.impl.SimpleLog"; logClassName = "org.apache.commons.logging.impl.SimpleLog";
} }
logDiagnostic("Using log class " + logClassName);
return (logClassName); return (logClassName);
} }
@@ -368,24 +461,48 @@ public class LogFactoryImpl extends LogFactory {
String logClassName = getLogClassName(); String logClassName = getLogClassName();
// Attempt to load the Log implementation class // Attempt to load the Log implementation class
//
// Question: why is the loginterface being loaded dynamically?
// Isn't the code below exactly the same as this?
// Class logInterface = Log.class;
Class logClass = null; Class logClass = null;
Class logInterface = null; Class logInterface = null;
try { try {
ClassLoader cl = this.getClass().getClassLoader(); ClassLoader cl = getClassLoader(this.getClass());
// handle the case if getClassLoader() returns null if (cl == null) {
// It may mean this class was loaded from the bootstrap classloader // we are probably in Java 1.1, but may also be running in
logInterface = (cl == null) ? loadClass(LOG_INTERFACE) : // some sort of embedded system..
cl.loadClass(LOG_INTERFACE); logInterface = loadClass(LOG_INTERFACE);
} else {
// normal situation
logInterface = cl.loadClass(LOG_INTERFACE);
}
logClass = loadClass(logClassName); logClass = loadClass(logClassName);
if (logClass == null) { if (logClass == null) {
logDiagnostic(
"Unable to find any class named [" + logClassName + "]"
+ " in either the context classloader"
+ " or the classloader that loaded this class.");
throw new LogConfigurationException throw new LogConfigurationException
("No suitable Log implementation for " + logClassName); ("No suitable Log implementation for " + logClassName);
} }
if (!logInterface.isAssignableFrom(logClass)) { if (!logInterface.isAssignableFrom(logClass)) {
LogConfigurationException ex = reportInvalidLogAdapter(logInterface, logClass); // oops, we need to cast this logClass we have loaded into
// a Log object in order to return it. But we won't be
// able to. See method reportInvalidLogAdapter for more
// information.
LogConfigurationException ex =
reportInvalidLogAdapter(logInterface, logClass);
throw ex; throw ex;
} }
} catch (Throwable t) { } catch (Throwable t) {
logDiagnostic(
"An unexpected problem occurred while loading the"
+ " log adapter class: " + t.getMessage());
throw new LogConfigurationException(t); throw new LogConfigurationException(t);
} }
@@ -411,9 +528,23 @@ public class LogFactoryImpl extends LogFactory {
/** /**
* Report a problem loading the log adapter, then <i>always</i> throw * Report a problem loading the log adapter, then <i>always</i> throw
* a LogConfigurationException. * a LogConfigurationException.
* * <p>
* @param logInterface * There are two possible reasons why we successfully loaded the
* @param logClass * specified log adapter class then failed to cast it to a Log object:
* <ol>
* <li>the specific class just doesn't implement the Log interface
* (user screwed up), or
* <li> the specified class has bound to a Log class loaded by some other
* classloader; Log@classloaderX cannot be cast to Log@classloaderY.
* </ol>
* <p>
* Here we try to figure out which case has occurred so we can give the
* user some reasonable feedback.
*
* @param logInterface is the class that this LogFactoryImpl class needs
* to return the adapter as.
* @param logClass is the adapter class we successfully loaded (but which
* could not be cast to type logInterface).
*/ */
private LogConfigurationException reportInvalidLogAdapter( private LogConfigurationException reportInvalidLogAdapter(
Class logInterface, Class logClass) { Class logInterface, Class logClass) {
@@ -421,6 +552,21 @@ public class LogFactoryImpl extends LogFactory {
Class interfaces[] = logClass.getInterfaces(); Class interfaces[] = logClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) { for (int i = 0; i < interfaces.length; i++) {
if (LOG_INTERFACE.equals(interfaces[i].getName())) { if (LOG_INTERFACE.equals(interfaces[i].getName())) {
if (isDiagnosticsEnabled()) {
ClassLoader logInterfaceClassLoader = getClassLoader(logInterface);
ClassLoader logAdapterClassLoader = getClassLoader(logClass);
Class logAdapterInterface = interfaces[i];
ClassLoader logAdapterInterfaceClassLoader = getClassLoader(logAdapterInterface);
logDiagnostic(
"Class " + logClassName + " was found in classloader "
+ objectId(logAdapterClassLoader)
+ " but it implements the Log interface as loaded"
+ " from classloader " + objectId(logAdapterInterfaceClassLoader)
+ " not the one loaded by this class's classloader "
+ objectId(logInterfaceClassLoader));
}
throw new LogConfigurationException throw new LogConfigurationException
("Invalid class loader hierarchy. " + ("Invalid class loader hierarchy. " +
"You have more than one version of '" + "You have more than one version of '" +
@@ -433,16 +579,7 @@ public class LogFactoryImpl extends LogFactory {
("Class " + logClassName + " does not implement '" + ("Class " + logClassName + " does not implement '" +
LOG_INTERFACE + "'."); LOG_INTERFACE + "'.");
} }
/**
* Gets the context classloader.
* This method is a workaround for a java 1.2 compiler bug.
*/
protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
return LogFactory.getContextClassLoader();
}
/** /**
* MUST KEEP THIS METHOD PRIVATE. * MUST KEEP THIS METHOD PRIVATE.
* *
@@ -453,7 +590,10 @@ public class LogFactoryImpl extends LogFactory {
* </p> * </p>
* *
* Load a class, try first the thread class loader, and * Load a class, try first the thread class loader, and
* if it fails use the loader that loaded this class. * if it fails use the loader that loaded this class. Actually, as
* the thread (context) classloader should always be the same as or a
* child of the classloader that loaded this class, the fallback should
* never be used.
*/ */
private static Class loadClass( final String name ) private static Class loadClass( final String name )
throws ClassNotFoundException throws ClassNotFoundException
@@ -489,12 +629,17 @@ public class LogFactoryImpl extends LogFactory {
*/ */
protected boolean isJdk13LumberjackAvailable() { protected boolean isJdk13LumberjackAvailable() {
// note: the algorithm here is different from isLog4JAvailable.
// I think isLog4JAvailable is correct....see bugzilla#31597
logDiagnostic("Checking for Jdk13Lumberjack.");
try { try {
loadClass("java.util.logging.Logger"); loadClass("java.util.logging.Logger");
loadClass("org.apache.commons.logging.impl.Jdk13LumberjackLogger"); loadClass("org.apache.commons.logging.impl.Jdk13LumberjackLogger");
return (true); logDiagnostic("Found Jdk13Lumberjack.");
return true;
} catch (Throwable t) { } catch (Throwable t) {
return (false); logDiagnostic("Did not find Jdk13Lumberjack.");
return false;
} }
} }
@@ -508,6 +653,9 @@ public class LogFactoryImpl extends LogFactory {
*/ */
protected boolean isJdk14Available() { protected boolean isJdk14Available() {
// note: the algorithm here is different from isLog4JAvailable.
// I think isLog4JAvailable is correct....
logDiagnostic("Checking for Jdk14.");
try { try {
loadClass("java.util.logging.Logger"); loadClass("java.util.logging.Logger");
loadClass("org.apache.commons.logging.impl.Jdk14Logger"); loadClass("org.apache.commons.logging.impl.Jdk14Logger");
@@ -515,9 +663,11 @@ public class LogFactoryImpl extends LogFactory {
if (throwable.getDeclaredMethod("getStackTrace", null) == null) { if (throwable.getDeclaredMethod("getStackTrace", null) == null) {
return (false); return (false);
} }
return (true); logDiagnostic("Found Jdk14.");
return true;
} catch (Throwable t) { } catch (Throwable t) {
return (false); logDiagnostic("Did not find Jdk14.");
return false;
} }
} }
@@ -527,12 +677,16 @@ public class LogFactoryImpl extends LogFactory {
*/ */
protected boolean isLog4JAvailable() { protected boolean isLog4JAvailable() {
logDiagnostic("Checking for Log4J");
try { try {
loadClass("org.apache.commons.logging.impl.Log4JLogger").getClassLoader() Class adapterClass = loadClass("org.apache.commons.logging.impl.Log4JLogger");
.loadClass("org.apache.log4j.Logger" ); ClassLoader cl = getClassLoader(adapterClass);
return (true); Class loggerClass = cl.loadClass("org.apache.log4j.Logger" );
logDiagnostic("Found Log4J");
return true;
} catch (Throwable t) { } catch (Throwable t) {
return (false); logDiagnostic("Did not find Log4J");
return false;
} }
} }