Ignatia sent me a question about classloaders (at the end of this), but after writing a long response I thought it was worth mailing to the list too so folk can comment/critique. The issue is the common one of not getting log4j to initialise properly after creating your own log4j.properties and removing the one in axis.jar.
Ignatia, it seems you must have your log4j.jar and log4j.properties being loaded by different classloaders. I suspect your axis.jar is in tomcat's common/lib folder. The rest of this email explains whats going on and what the possible setups are. There are two issues involved here: the arcane rules of classloaders and which class references what. The explanation below is for tomcat 4 (ie servlet 2.3 spec) - tomcat 3 is a servlet 2.2 implementation and classloader order is DIFFERENT. Its also my understanding which may only apply in a parallel universe... A typical jaxrpc usage begins with sf=javax.xml.rpc.ServiceFactory.newInstance(); this in turn loads an axis implementation of the service[2]. Axis then invokes commons-logging to set up its logging mechansim. commons-logging then invokes log4j if installed, and finally log4j's basicconfigurator loads log4j.properties. So the loading sequence is: jaxrpc -> axis -> commons-logging -> log4j -> log4j.properties Now look at http://jakarta.apache.org/tomcat/tomcat-4.0-doc/class-loader-howto.html, especially this diagram showing how the classloaders fit together: Bootstrap | System | Common / \ Catalina Shared / \ Webapp1 Webapp2 ... if jaxrpc is loaded by the 'common' classloader, it can only see up the tree to 'System' and 'Bootstrap'. This means if you install jaxrpc in the 'common/lib' folder in tomcat, you MUST install axis.jar[1], commons-logging.jar, log4j.jar in there too for them to be found. log4j.properties must be in one of these jars or in 'common/classes' to be found. If you place commons-logging, log4j, and log4j.properties in your webapp (as well as placing everything in 'common' as above), you will get logging working, but in a way that may surprise you. While axis now gets the common log4j, your webapp gets its own instance of log4j. This means you can change where your webapp logs to, but not the axis parts of it! Axis will keep on using the common log4j.jar. Things get even more confused if you set your system classpath to contain jaxrpc (rather than putting it in the common directory). Again you have the same 'sucking' effect where you end up having to put log4j.properties in the same classpath as jaxrpc. However, now you'll find you can't override the log4j.properties at all on a per-webapp basis. The reason is in tomcat's javadoc for WebappClassLoader: "The system class loader will be queried first, then the local repositories, and only then delegation to the parent class loader will occur. This allows the web application to override any shared class except the classes from J2SE" The way I read this, if log4j.properties(A) was in the system classpath and log4j.properties(B) was in WEB-INF/classes, then (A) would be read FIRST. If log4j.jar was in the system classpath, and log4j.properties is only in the webapp, then it /wont load at all/ as now log4j can no longer 'see' the webapp's classpath. Summing up so far, there are three possible working setups where your webapp uses commons-logging. COMMON LOGGING: every webapp gets the same log common/lib/jaxrpc.jar common/lib/axis.jar #etc common/lib/commons-logging.jar common/lib/log4j.jar common/classes/log4j.properties COMMON AXIS LOGGING: same axis log, separate webapp logs common/lib/jaxrpc.jar common/lib/axis.jar #etc common/lib/commons-logging.jar common/lib/log4j.jar common/classes/log4j.properties webapps/app/WEB-INF/lib/commons-logging.jar webapps/app/WEB-INF/lib/log4j.jar webapps/app/WEB-INF/classes/log4j.properties SEPARATE LOGGING: suck it and see webapps/app/WEB-INF/lib/jaxrpc.jar webapps/app/WEB-INF/lib/axis.jar #etc webapps/app/WEB-INF/lib/commons-logging.jar webapps/app/WEB-INF/lib/log4j.jar webapps/app/WEB-INF/classes/log4j.properties this last one is interesting. Tomcat's WebappClassloader uses a different delegation model for 'javax.*' - these classes are searched for in the parent classloader first, then in the webapps own repository. The upshot of this is that a shared jaxrpc will ALWAYS be found first, and if it is found, separate logging WILL FAIL. That's why I've not listed any classes in common/* for this solution. There is still one stumbling block in the way of having separate logging for axis on a per-webapp basis, and its this line in happyaxis.jsp: "On Tomcat 4.x, you may need to put libraries that contain java.* or javax.* packages into CATALINA_HOME/commons/lib", see also http://xml.apache.org/axis/faq#faq5 This jars a bit with my understanding. Tomcat won't let me override anything in the system classpath (ie anything in the jdk) using a simple mechanism - it checks in the system classloader first for everything. The only other filter for "javax" stuff ensures that the parent classloaders are searched first, as described above. This means that if you have no jaxrpc.jar in your jdk or in tomcat's common area, you can use a different jaxrpc for each webapp. Which means (finally) that you should be able to have separate axis logs for each webapp. I should emphasise that I've not tried all of this - my setup already was the 'common logging' one before I started using axis. Anyway. Anyone care to poke holes in the logic? Does anyone actually have separate axis logs for different webapps working? -Baz [1] I'm using axis.jar as shorthand for all the rest of the axis jars here too. [2] if you invoke axis directly as you did before jaxrpc appeared, then you lose portablility, but none of the restrictions on the placement of jaxrpc.jar mentioned at the end of the article apply. Ignatia Suwarna wrote: > Hi Brian, > > I read your email about Log4j from Axis mailing list. > I am having similar trouble and would like to ask for your suggestions. > > I changed log4j.properties from axis.jar: > # Set root category priority to ERROR and its only appender to A1. > log4j.rootCategory=INFO, LOGFILE > log4j.category.org.apache.axis=INFO, LOGFILE > #log4j.rootCategory=DEBUG, CONSOLE, LOGFILE > > # CONSOLE is set to be a ConsoleAppender using a PatternLayout. > log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender > log4j.appender.CONSOLE.Threshold=INFO > log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout > log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n > > # LOGFILE is set to be a File appender using a PatternLayout. > log4j.appender.LOGFILE=org.apache.log4j.FileAppender > >log4j.appender.LOGFILE.File=C:\Netscape\Servers\bin\https\webapps\axis\WEB-INF\classes\axis.log > log4j.appender.LOGFILE.Append=true > log4j.appender.LOGFILE.Threshold=INFO > log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout > log4j.appender.LOGFILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - > %m%n > > I also set up the path in my servlet to point to lo4j.properties in > \WEB-INF\classes directory. I have removed log4j.properties from > axis.jar. > > I am getting this error: > log4j:ERROR No appenders could be found for category > (org.apache.axis.utils.Opti > ons). > log4j:ERROR Please initialize the log4j system properly. > AxisFault > > Do you know how to resolve this? Am I missing something else? > > I would really appreciate any suggestions/help. > > Thank you very much. > > Ignatia Suwarna > > >
