First of all, I never use Jakarta Commons Logging (JCL) directly in my applications (Log4J is my tool of choice for logging tasks), but as you probably know many frameworks and libraries do all of their logging through JCL. In most cases you will want to catch some of these log messages, so that you can better monitor your application. For example, you will probably want to log all SQL queries that Hibernate issues, at least in the early development phase, so that you can have a better perspective of what is going on.
I usually don’t have a problem with JCL since it finds a Log4J implementation in the classpath, get my configuration and all works fine. Except when it doesn’t.
In this particulair case, I had a Spring-Hibernate based web application that I needed to deploy on the Tomcat 5 server. After deploying an application, commons logging couldn’t find a log4j implemantation and all logs were redirected to the standard Tomcat log file.
Your first reaction will probably be: “This one is easy, just put you log4j jar in the server classpath (commons/lib folder probably) and all should be fine”. While it should be a no-brainer task, it is a bit more complex then that.
The root of the problem is that Tomcat 5 has a commons-logging-api.jar file in the bin/ folder. This jar is hardcoded in the booting procedure and loaded during the Tomcat boot time in order to be used for server logging tasks. All attempts to use some other JCL classes will be ignored by Tomcat. The problem is caused by the fact that this version of JCL does not contain a log4j addapter.
Even though JCL troubleshooting section says that putting appropriate JCL and Log4J jars in the WEB-INF/lib folder should work, it doesn’t.
After some searching and experimenting I managed to find a solution that works for me:
- First of all, we need to replace
commons-logging-api.jarin thebin/folder with the full JCL implementation. Note that jar filename must becommons-logging-api.jar, since it is hardcoded in the Tomcat boot routine. Also, be sure that you use version 1.0.4 (or newer) or you will have problems in trying to stop your application. -
The second step is to put an appropriate version of the log4j jar in the
common/endorsedfolder.
Now it should be working in the same manner as on all other servlet containers. I’m interested if anyone else had some similar expiriences and what techniques were used to soved these kinds of issues. Also, it is a shame that this is not properly documented.



Have you checked out http://www.slf4j.org/ yet? IMHO, it's the way to go for projects that want to use "generic" logging.
oran
See also http://www.qos.ch/logging/classloader.jsp, in case you haven't come across it.
This is a known problem for working with IBM WebSphere years ago.
See the following link for the cause and solution:
http://www-1.ibm.com/support/docview.wss?uid=swg27004610
It's also the fact that the server uses JCL itself.
We put the log4j.jar in WEB-INF/lib and log4j.properties in WEB-INF/classes on Tomcat 5.0.28. Works just fine.
Classloading is a top gotcha for J2EE development. The Tomcat site has a nice description of how it works. Basicly the various 'lib' directories are managed by separate loaders.
The problem arrises for library pairs such as JCL+log4j or Tapestry+HiveMind. As one manipulates the other they need to be loaded with the same class loader.
Your fix may work, but its bad practice to meddle with the containers private jar's. Instead just put commons-logging.jar & log4j.jar in WEB-INF/lib, and it will work just fine. Make sure that they are not in shared/lib or common/lib.
Additionally you need a snipped in a context listener to ensure that JCL releases it's references when you redeploy your webapp. Otherwise you get a memory leak.
I completely sympathize here. JCL and JUL annoy me to no end. Log4J was a perfectly good solution, and even if you accept it as an "implementation" for the other specs, they always have some kind of "ism" that annoys me to no end.
My solution is to leave commons-logging-api.jar in bin/ folder and to put:
- log4j.jar and commons-logging.jar to common/lib/ folder
- log4j.properties (tomcat logging properties) to common/classes/
Now there are two choices:
- when web app doesn't have commons-logging.jar in WEB-INF/lib, it uses server-wide JCL+Log4J configuration
- when web app wants to use its own JCL config, it has to have commons-logging.jar, log4j.jar in WEB-INF/lib AND log4j.xml in WEB-INF/classes.
This configuration uses the fact, that Log4J static{} configuration first looks up log4j.xml and then log4j.properties.
In my opinion this is better approach then to use e.g. Spring's Log4jConfigListener, because it works immediately after creating web-app class loader by Tomcat.
Grzegorz Grzybek
The whole point of commons.logging is that it doesn't create an unnecessary dependency on log4j or the jdk logging api. You should distinguish between functionality for logging messages and for configuring the logging. These are two things. Use commons.logging for the first and whatever suits best you for the latter.
Personally I get really annoyed when I need to use some library or component that insists on using log4j because it breaks the jdk logging api configuration I have set up in my container. In general this is not an issue because libraries shouldn't log anything (at least not above FINE level) but sadly some do insist on spoiling my logs with pointless information and then make matters worse by forcefeeding me log4j. E.g. hibernate lacks a STFU option and seems to be bundled with log4j.
What most log4j users don't understand is that logging configuration should be taken care of at the container level and not at the library or application level. In other words, if you are depending on log4j at the application level you are probably messing with stuff that is better done elsewhere. Your application is a source and not a consumer of logging information.
It seems putting commons-logging.jar and log4j.jar in your-webapp/WEB-INF/lib and putting log4j.xml in your-webbapp/WEB-INF/classes is a recommended way. Yet i encounted a problem.
i created log/netmsg folder under my-webapp/WEB-INF, and here is part of my log4j.xml:
I intended to log to my-webapp/WEB-INF/log/netmsg/msgserver.log.
When i started tomcat, it throws exception:
log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: ..\log\netmsg\msgserver.lo
But if i created log/netmsg folder under tomcat-home folder, this exception won't be thrown. So it seems like commons-logging-api.jar in the bin folder will try to read my log4j.xml, and configure the logging setting according to it.
obvious it's not what i want. can somebody please help me?
Dejan, you saved my day!
Situation: Tomcat 5.5.20, log4j.jar only in our WEB-INF/lib. Today a new application component required commons-logging-1.1.jar in WEB-INF/lib, so we added it => low level Tomcat debug messages everywhere, immediately suffocating any useful application output. I knew it's about JCL, but haven't even dreamed of replacing the original bin\commons-logging-api.jar (1.0.4) to our version (1.1).
It helped, Thanks!
Hi ,
i have application in tomcat clarityweb/web-inf/lib i have all jar i have removed log4j.properties from my tomcat folder even though it is picking up from some other place even i have searched the file through out the folder but no use , its picking up by some other place am unable to notice that culprit. plz hgelp me out from this
thanks
venkat
Ich erklare meinen Freunden uber diese Seite. Interessieren!
Interesting comments.. :D
Same problem when deploying axis2 into Tomcat 5.5.25. Axis2 did not pickup any log4j stuff which it has a denpendy on. I have actually tried the same tactics of renaming my commons-logging-1.1.jar into commons-logging.api.jar and placed it under Tomcat-5.5.25\bin folder. But the axis2 did not work out for me. Any suggestions. (JDK1.6_03, Axis2 1.3)
it works with log4j as described in the Apache Tomcat documentation. My problem I have to fight with is going further. We use our own logging framework, which is distributed as a component and resides in a web app. We have upgraded to the new FOP 0.94, which now uses commons logging. The challenge is to catch the log output from FOP and redirect it to our own logger - and make it on the application level. Attempts to set the logging implementation in the app fails with "Call too late" error, because Tomcat configures commons logging on start-up. I would not be willing to place own components in common\libs as, how logging is performed is a matter of the web app. How would you guys solve the problem?
Thank you!
I have tried the steps. Now i am able to start the server. However i am not able to see the log messages in the console, as it is giving a warning message as below.
log4j:WARN No appenders could be found for logger (org.apache.catalina.startup.ClassLoaderFactory).
log4j:WARN Please initialize the log4j system properly.
I have kept my log4j.properties under commons/classes folder. Please let me know if i am missing something.
Regards..
Debadatta