On 5 Aug 2004, at 18:23, Shapira, Yoav wrote:
Hola,
i'm not sure i understand what ceki's point is. i can't see that he gives any reason for pointing the finger in the way he does. maybe if ceki explained how using classloaders as keys effects log4j, i'd see a bit better...
The issue is: - Web application deployed on Tomcat uses log4j via commons-logging - When said application is restarted (using one of the methods provided by Tomcat do restart a webapp without restarting the Tomcat server itself), a java.lang.ThreadDeath exception is thrown when commons-logging calls a log4j logging function. - We suspect this exception is thrown by Tomcat because the ClassLoader used by commons-logging to load the log4j class is invalid. But it's still the cache key in the commons-logging cache. It's invalid because when restarting a webapp Tomcat provides it with a new set of classloaders per the Servlet Specification.
i still don't understand how this could produce the stack trace:
SEVERE: Exception invoking periodic operation:
java.lang.ThreadDeath
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader .java:1229)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader .java:1189)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at org.apache.log4j.spi.LoggingEvent.<init>(LoggingEvent.java:241)
at org.apache.log4j.Category.forcedLog(Category.java:431)
at org.apache.log4j.Category.log(Category.java:966)
at org.apache.commons.logging.impl.Log4JLogger.error(Log4JLogger.java:195)
at org.apache.catalina.session.StandardManager.start(StandardManager.java: 659)
at org.apache.catalina.core.StandardContext.start(StandardContext.java: 4272)
at org.apache.catalina.core.StandardContext.reload(StandardContext.java: 3021)
at org.apache.catalina.core.StandardContext.backgroundProcess(StandardConte xt.java:4629)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.proc essChildren(ContainerBase.java:1619)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.proc essChildren(ContainerBase.java:1628)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.proc essChildren(ContainerBase.java:1628)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run( ContainerBase.java:1608)
at java.lang.Thread.run(Unknown Source)
i can't see the LogFactory anywhere in the trace. you're probably more familiar with the tomcat reloading code than i but when i look at the StandardManager.start code in CVS HEAD of jakarta-tomcat-catalina, i can't see the sequence of events starting with the LogFactory cache that would lead to the problem. StandardManager already has an Log4JLogger instance created by (i believe) either the context or thread classloader of the thread used to load the StandardManager instance. no special classloader magic is used to load the Logger but it is lazily loaded.
the commons-logging classloader stuff was created IIRC by craig, remy and others. i don't feel qualified to second-guess their knowledge of servlet containers.
You recall correctly as far as Craig ;) We're not second-guessing their
knowledge or even their implementation. But the Tomcat webapp reloading
code has evolved sufficiently since the initial creation of
commons-logging's cache implementation that now the two are not playing
perfectly together.
i'm still not convinced that the classloader map has anything to do with it.
i'm more interested in the classloaders which tomcat is using. could be that the classloader configuration used by tomcat when it loads StandardManager leads to the LogFactory logic chosing a bad classloader.
in terms of things that will fix this issue, the easiest way would be to simply catch all throwables in Log4JLogger. this would be an appropriate solution so long as this problem is intermittent.
i've wanted for a while to use a WeakHashMap so that old classloaders who be garbage collected but don't see that there's an easy way to do this without breaking compatibility.
What would break if we switched commons-logging to use such a WeakHashMap instead of the currently used normal HashMap?
a hashtable is used but it's exposed :(
i think that there are ways round this so long as we're willing to sacrifice symantic compatibility for subclasses. there are a lot of improvements that could be made to commons-logging but it isn't a particular itch of mine and i don't have a lot of energy to spare. of course, i'd be happy to give whatever help i could to others if they felt differently.
- robert
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
