Thanks Simon,
Simon Kitching schrieb:
On Wed, 2005-05-18 at 12:20 +0200, David Perez wrote:
You're right, I have changed the commons-logging version to the latest one.
Now I have reverted to commons-logging-1.0.2
I would recommend using commons-logging-1.0.4. After all, that is the most recent official release.
I have already done so successfully. See below for more details.
From my code I call LogFactory.releaseAll() after removing the old web app context, and no luck :-(I suggest registering a ServletContextListener. Declare a <listener> element in the web.xml file, with a nested <listener-class> element containing the fully qualified classname of a logging-cleanup class. In the contextDestroyed method of that class do this: * LogFactory.release( Thread.currentThread().getContextClassLoader()) * somehow cleaning up the underlying logging library if needed.
If that doesn't help, let me know and we can look into it a bit
further.
Do you mean that you use a ServletContextListener as I described? Or something else?
Note also that LogFactory.releaseAll may not do what you want. If your webapp has bound to commons-logging that is loaded via a shared classloader, then calling releaseAll will shut down *all* instances of commons-logging - which other webapps running in the same container may not appreciate :-). The code I recommended will only shut down logging for the webapp whose context is being destroyed, assuming you are calling the method from a SerletContextListener.contextDestroyed, ie from code where Thread.currentThread.getContextClassLoader() returns the classloader of the webapp being unloaded.
Now I use LogFactory.release()
Should my webapp use another copy of commons-logging.jar?
That depends.
If your webapp has all the libraries it needs in WEB-INF/lib, then yes. Deploying commons-logging.jar in WEB-INF/lib in that situation makes things very clean and consistent. There's no need to use call LogFactory.release() in this case, as undeploying the webapp automatically undeploys commons-logging and the underlying logging lib.
But if your webapp is calling into code that is deployed via a shared
classloader, and that code uses commons-logging, then you must *not*
also deploy commons-logging in WEB-INF/lib. If you do (and you are using
release 1.0.4), you will get the message
Invalid class loader hierarchy. You have more than one version of org.apache.commons.logging.Log
visible, which is not allowed.
If you are using an earlier release, you will probably get something
like:
AvalonLogger does not implement Log
Finally I use a shared instance.
Avalon LogKit can be configured to use the Log4J subsystem. I like more Log4J than Avalon LogKit.
Here is the logging jars I use in my app:
jars used by the web server (Jetty):
* commons-logging.jar and * log4j.jar
jars used by the webapp:
* logkit.jar
My web app uses Cocoon which uses Avalon LogKit, and makes me include logkit.jar, even though logging is redirected to log4j.
What do you mean "logging is redirected to log4j"?
You were right, I had a WEB-INF/classes/common-logging.properties file, of my webapp, that I used to use before I decided to use log4j instead of LogKit. Commons-loggind 1.02 did ignore this file, but version 1.0.4 didn't. This what has confused me.Some other classes use directly commons-logging
With commons-logging-1.0.4 and 1.05 alpha1, I have to make logkit.jar available to Jetty, otherwise commons-loggings throws a ClassNotFoundException, because it cannot find
org/apache/log/Hierarchy. I wonder why it tries to load LogKit if Log4j is already available?
Commons-logging does *not* auto-discover LogKit; it doesn't even try. So
somewhere something in your webapp must be *ordering* commons-logging to
use AvalonLogger (aka LogKit) as the logger.
Which logging lib commons-logging uses can be explicitly set via a number of methods; .properties files, jdk1.3 service files, system properties. See the commons-logging documentation for more information.
I load it programmatically with a call to
Caused by: java.lang.NoClassDefFoundError: org/apache/log/Hierarchy
at org.apache.commons.logging.impl.LogKitLogger.getLogger(LogKitLogger.java:77)
at org.apache.commons.logging.impl.LogKitLogger.<init>(LogKitLogger.java:64)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
Yep, commons-logging's LogFactoryImpl is explicitly trying to
instantiate a LogKitLogger object.
Can you please:
(a) look for what is ordering commons-logging to use LogKit and remove
that?
(b) use commons-logging 1.0.4; I will be able to help you much better
than if you use the very old 1.0.2.
Also, can you please confirm that Jetty (and your webapp) use the standard child-first (aka parent-last) classloading order? I know the Resin webserver doesn't, and that makes things quite different...
And by the way, where do you put your log4j configuration file?
PropertyConfigurator.configureAndWatch(new File(basedir, "logs/"+System.getProperty("loggging.file", "log-production.properties")).toString());
in this way I can
1. change dynamically the logging configuration 2. have two sets of logging configurations: one for production (the default) and other for development (overriden through a system property in the debug launch). In this way, increasing log level for testing purposes never goes to production inadvertently.
Good luck!Now I have only problems with log4j and some other static instances, but not with commons-logging!!
Thanks for your invaluable help.
David