Announcement Announcement Module
Collapse
No announcement yet.
Remove Commons Logging in favor of Log4j 1.3 UGLI Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Remove Commons Logging in favor of Log4j 1.3 UGLI

    When Log4j 1.3 comes out it, it will be suggesting that people use UGLI (funny ackronym) rather than Jakarta Commons Logging (JCL) due to the class loading hell it causes as described in this doc:

    http://www.qos.ch/logging/classloader.jsp

    Here is the UGLI documentation link:
    http://logging.apache.org/log4j/docs/ugli.html

    You basically use it just like JCL. My main rant is that I would rather call a log variable "log" rather than "logger". Less typing. I would also just like 1 import if at all possible.

    Both future version of Jetty and XMLC look like they will be switching. It seams like a better way to do it. I'm wondering if Spring might switch in a future version.

    Cameron

  • #2
    We haven't thought of switching at this point. It would be interesting to try to discuss any switch across popular packages like Spring/Struts etc. that presently use Commons Logging. Otherwise, just one project switching on its own isn't likely to make much difference.

    Comment


    • #3
      Originally posted by Rod Johnson
      Otherwise, just one project switching on its own isn't likely to make much difference.
      I agree. If the packages I depend on still use Jakarata Commons Logging (JCL), then I still have to deal with the classloading issues from it and it doesn't make much sense for me to move away from it. That is why I brought it up to you, because I'll probably follow.

      I would be interested in finding out what the Hibernate and Tomcat teams think of it as well. Hopefully, there will be more traction/publicity when Log4j 1.3 is released. It seams like a pretty simple search and replace.

      Cameron

      Comment


      • #4
        Is UGLI pronounced "ugly"?

        Comment


        • #5
          And when I first read about UGLI = Universal and Generic Logging Interface, the first thought was, "hmm, so now someone came up with something else to abstract away commons-logging?"

          Comment


          • #6
            I agree...it would be nice to see Spring switch from JCL to something else for the reasons those articles mention. I'm having class loading issues that I can only resolve by putting the commons-logging, spring, and hibernate jars in the system classpath (yuk!).

            My situation is I have one service that calls another service. Each service is it's own application in WebLogic and thus has its own classloader. I am seeing JCL.jar conflicts despite the fact that they should be isolated. I wonder if maybe I could take a different approach to loading the applicationContext rather than using ClassPathXmlApplicationContext and maybe specify the classloader myself through XmlBeanDefinitionReader (the abstract parent class allows you to specify the classloader). Spring defaults to the contextLoader. Has anyone had any experience trying this? Has anyone found any workarounds to JCL classloader hell??

            This is the error I'm seeing:
            Code:
            Object=org.springframework.orm.hibernate.SessionFactoryUtils$JtaSessionSynchronization@2b04839, Exception=java.lang.ExceptionInInitializerError
            java.lang.ExceptionInInitializerError
            at net.sf.hibernate.util.JDBCExceptionReporter.logWarnings(Ljava.sql.SQLWarning;)V(JDBCExceptionReporter.java:???)
            at net.sf.hibernate.impl.BatcherImpl.closeConnection(Ljava.sql.Connection;)V(BatcherImpl.java:297)
            at net.sf.hibernate.impl.SessionImpl.disconnect()Ljava.sql.Connection;(SessionImpl.java:3352)
            at net.sf.hibernate.impl.SessionImpl.close()Ljava.sql.Connection;(SessionImpl.java:576)
            at org.springframework.orm.hibernate.SessionFactoryUtils.doClose(Lnet.sf.hibernate.Session;)V(SessionFactoryUtils.java:651)
            at org.springframework.orm.hibernate.SessionFactoryUtils.closeSessionOrRegisterDeferredClose(Lnet.sf.hibernate.Session;Lnet.sf.hibernate.SessionFactory;)V(SessionFactoryUtils.java:640)
            at org.springframework.orm.hibernate.SessionFactoryUtils.access$300(Lnet.sf.hibernate.Session;Lnet.sf.hibernate.SessionFactory;)V(SessionFactoryUtils.java:86)
            at org.springframework.orm.hibernate.SessionFactoryUtils$SpringSessionSynchronization.beforeCompletion()V(SessionFactoryUtils.java:776)
            at org.springframework.orm.hibernate.SessionFactoryUtils$JtaSessionSynchronization.afterCompletion(I)V(SessionFactoryUtils.java:874)
            at weblogic.transaction.internal.ServerSCInfo.callAfterCompletions(I)V(ServerSCInfo.java:853)
            at weblogic.transaction.internal.ServerTransactionImpl.callAfterCompletions()V(ServerTransactionImpl.java:2708)
            at weblogic.transaction.internal.ServerTransactionImpl.afterCommittedStateHousekeeping()V(ServerTransactionImpl.java:2606)
            at weblogic.transaction.internal.ServerTransactionImpl.setCommitted()V(ServerTransactionImpl.java:2638)
            at weblogic.transaction.internal.ServerTransactionImpl.globalRetryCommit(II)V(ServerTransactionImpl.java:2436)
            at weblogic.transaction.internal.ServerTransactionImpl.globalCommit()V(ServerTransactionImpl.java:2365)
            at weblogic.transaction.internal.ServerTransactionImpl.internalCommit()V(ServerTransactionImpl.java:278)
            at weblogic.transaction.internal.ServerTransactionImpl.commit()V(ServerTransactionImpl.java:244)
            at weblogic.ejb20.internal.BaseEJBObject.postInvoke(Lweblogic.ejb20.internal.InvocationWrapper;Ljava.lang.Throwable;)V(BaseEJBObject.java:299)
            at weblogic.ejb20.internal.StatelessEJBObject.postInvoke(Lweblogic.ejb20.internal.InvocationWrapper;Ljava.lang.Throwable;)V(StatelessEJBObject.java:140)
            at com.bea.wlw.runtime.core.bean.SyncDispatcher_k1mrl8_EOImpl.invoke(Lcom.bea.wlw.runtime.core.request.Request;)Lcom.bea.wlw.runtime.core.request.Response;(SyncDispatcher_k1mrl8_EOImpl.java:110)
            at com.bea.wlw.runtime.core.dispatcher.Dispatcher.remoteDispatch(Lcom.bea.wlw.runtime.core.dispatcher.DispFile;Lcom.bea.wlw.runtime.core.request.Request;)Lcom.bea.wlw.runtime.core.request.Response;(Dispatcher.java:161)
            at com.bea.wlw.runtime.core.dispatcher.Dispatcher.dispatch(Lcom.bea.wlw.runtime.core.dispatcher.DispFile;Lcom.bea.wlw.runtime.core.request.Request;Ljavax.servlet.http.HttpServletResponse;Ljavax.servlet.ServletContext;)V(Dispatcher.java:49)
            at com.bea.wlw.runtime.core.dispatcher.HttpServerHelper.executePostRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;Ljavax.servlet.ServletContext;Ljavax.servlet.ServletConfig;)V(HttpServerHelper.java:713)
            at com.bea.wlw.runtime.core.dispatcher.HttpServer.doPost(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServer.java:49)
            at javax.servlet.http.HttpServlet.service(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServlet.java:760)
            at javax.servlet.http.HttpServlet.service(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(HttpServlet.java:853)
            at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run()Ljava.lang.Object;(ServletStubImpl.java:996)
            at weblogic.servlet.internal.ServletStubImpl.invokeServlet(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;Lweblogic.servlet.internal.FilterChainImpl;)V(ServletStubImpl.java:419)
            at weblogic.servlet.internal.ServletStubImpl.invokeServlet(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(ServletStubImpl.java:315)
            at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run()Ljava.lang.Object;(WebAppServletContext.java:6456)
            at weblogic.security.acl.internal.AuthenticatedSubject.doAs(Lweblogic.security.subject.AbstractSubject;Ljava.security.PrivilegedAction;)Ljava.lang.Object;(AuthenticatedSubject.java:321)
            at weblogic.security.service.SecurityManager.runAs(Lweblogic.security.acl.internal.AuthenticatedSubject;Lweblogic.security.acl.internal.AuthenticatedSubject;Ljava.security.PrivilegedAction;)Ljava.lang.Object;(SecurityManager.java:118)
            Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed. (Caused by org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.) (Caused by org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed. (Caused by org.apache.commons.logging.LogConfigurationException: Invalid class loader hierarchy. You have more than one version of 'org.apache.commons.logging.Log' visible, which is not allowed.))
            at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(Ljava.lang.String;)Lorg.apache.commons.logging.Log;(LogFactoryImpl.java:543)
            at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(Ljava.lang.String;)Lorg.apache.commons.logging.Log;(LogFactoryImpl.java:235)
            at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(Ljava.lang.Class;)Lorg.apache.commons.logging.Log;(LogFactoryImpl.java:209)
            at org.apache.commons.logging.LogFactory.getLog(Ljava.lang.Class;)Lorg.apache.commons.logging.Log;(LogFactory.java:351)
            at net.sf.hibernate.util.JDBCExceptionReporter.<clinit>&#40;&#41;V&#40;JDBCExceptionReporter.java&#58;12&#41;
            at jrockit.vm.RNI.getRunnableCode&#40;I&#41;I&#40;Unknown Source&#41;
            at jrockit.vm.RNI.trampoline&#40;&#41;V&#40;Unknown Source&#41;

            Comment


            • #7
              update

              Hi, i was just wondering if you came to some conclusion in this area. UGLI is now SLF4J (http://www.slf4j.org/) and JCL is still a hell with ClassLoaders (one of the logs: http://issues.apache.org/bugzilla/show_bug.cgi?id=35774).
              Of course, Hibernate, Axis and tons of others still use JCL...

              thanks,
              d

              Comment


              • #8
                Why wait?

                Originally posted by Rod Johnson
                Otherwise, just one project switching on its own isn't likely to make much difference.
                So you're saying that Spring will change only if other project does it before? I like spring cause it is really simple and powerfull but have you noticed how many post relating to log config problems are in this forum? I know it isn't a spring fault but wouldn't be nice if spring (and perhaps other projects)would provide two distributions, one with JCL an other with SLF4J so spring users don't have to wait till other projects do it before.

                Yes, i know there still would be other project using JCL and we will has to face 2 facades but if no project wants to be first then how its supossed to achieve this goal.
                Last edited by edgarcruz; Nov 18th, 2005, 12:23 PM.

                Comment


                • #9
                  Gradual migration

                  SLF4J also allows for a gradual migration path away from JCL. For more details see http://www.slf4j.org/manual.html#gradual

                  Comment


                  • #10
                    It looks like release of JCL 1.0.5 is nearing that's supposed to fix most of the problems associated with multi-classloader environment.

                    Unfortunetely, some of the issues will probably go unfixed. One of the problems I keep running into is the log creation in the shared environment. For instance, we have Spring libraries deployed in the shared location (Tomcat's shared/lib).

                    I recently talked to Simon Kitching [[email protected]] on this issue and he pointed out:
                    Do you mean that you have a class in a "shared" location with this?
                    private static Log log = LogFactory.getLog("...");

                    The use of static fields for loggers in a class that may be shared is a
                    known issue and is described in the FAQ. The answer is to *not* use
                    static fields; make the logger an instance member.

                    Or even better, don't deploy classes in "shared" locations. I personally
                    believe this is not good design; applications in a container are meant
                    to be independent.
                    I don't really see a reason to move Spring to application's war instead of shared/lib. Spring is shared-lib and TCCL friendly, so I wanted to take advantage of this.

                    As for static logs, I noticed Spring's classes do use instance logs in many cases with exception of mainly helper classes, such as DataSourceUtils.

                    Would it be possible to get rid of the static logs for such classes? This would basically mean, that Spring is completely shared-CL friendly.

                    Comment


                    • #11
                      Originally posted by dvoytenko
                      I recently talked to Simon Kitching [[email protected]] on this issue and he pointed out:

                      Originally posted by Simon Kitching
                      Or even better, don't deploy classes in "shared" locations. I personally believe this is not good design; applications in a container are meant to be independent.
                      I agree with Simon -- putting libs in shared locations isn't the best way to go.

                      Problems that sharing libs can cause:
                      1. Class loader problems - you found this one
                      2. Independance - what if you want to deploy two instances of your app - one with spring 1.2 and one with 2.0?
                      3. Maintenance - like independance (above), good luck upgrading shared libs. I've had multiple apps deployed on the same servers that *required* different lib versions.

                      Additional benefits of libs in war:
                      1. App installation and removal is simplier.
                      2. Purity. wars/ears stay as "everything the app needs to work", just like they should be.
                      3. Lib version mismatch reduced.

                      Costs of libs in war:
                      1. Disk space? At most, a couple of megs of jars repeated a couple of times on any modern machine? Not an issue.
                      2. Memory space? Again, not enough to matter on modern machines.

                      In short, the savings of sharing libs is not worth the cost.

                      Comment


                      • #12
                        Hi,

                        Problems that sharing libs can cause:
                        Class loader problems - you found this one
                        Independance - what if you want to deploy two instances of your app - one with spring 1.2 and one with 2.0?
                        Maintenance - like independance (above), good luck upgrading shared libs. I've had multiple apps deployed on the same servers that *required* different lib versions
                        1) I don't belive Spring reports anywhere constraints of deployment in the shared locations. If this is the case, it would be fine. There's no class loader problems using it in such configurations. I don't have a problem deploying it with applications for Tomcat installation, and actually do deploy it this way. But in this case I'm not using a standard way of deploying just b/c of problems with logging.

                        2) While there're certainly problems with shared deployments, but the same is true with in-war deployments as well. Otherwise, managing dependencies from war deployment to shared lib deployment is not a huge problem, and probably is done for at least one library in the system.

                        3) Finally, the same issues related to Tomcat applications/shared hold for application server deployments, where you might be forced to deploy Spring outside of WAR files. The same problems will appear here.

                        In either case, JCL requirements to avoid static logs doesn't seem to be too harsh. But that would ensure appropriate work of the library in any environment.

                        Comment


                        • #13
                          I agree with the points pointed out by Blackstar. However, I also think that we should not stick with JCL.

                          Any experienced developer will know you can't always get your way to do think the way you think it should be done (to share libs or to package libs in war and uncountable other issues).

                          For example if your manager "who happens to comes from the 80s era background where the best programmer is the one who writes the same code with the least number of instructions" thinks every Mb saved is a Mb earned. We are not talking about best practises, but in situations in which you can't do so (ligitimate or not). I wouldn't use a framework that can only work well with 100% best practises only and fails miserably otherwise.

                          Even the JCL's original authors condemned JCL - I'm sure you guys read about it long ago.

                          I've never have too much problems with it (only once earlier in my university days.), but I think if a major component of the framework is flawed fundimentally, you should change it and not force ppl to work around it.

                          What I like about Spring is that it gives CHOICE. So if JCL is restricting how people are configuring their apps, something should be done.

                          I'm sure if enough people is complaining about it, the Spring guys will change it. Its about whether there is a need and demand to get it done (since its not essentially a bug with Spring) or to put the effort in more important problems/developments at hand.
                          Last edited by chunhui; Jan 9th, 2006, 03:14 AM.

                          Comment


                          • #14
                            Let me make a step back. I don't want to start the argument about "correct" deployment model for Spring or other components. I belive, if specifications allow different deployment models, someone might be using them (whether they're from 80s, 90s or 2000s). I never experienced problems with Spring framework in the shared deployment outside of JCL issues. So my point here is simply is that use of JCL seems to be the only issue that can disable this option, but there're certain steps that can be taken to preserve it (getting rid of static logs).

                            Comment


                            • #15
                              If this helps the argument - I did experience very nasty manifestation of JCL problems in Spring. And I wasn't happy. It wouldn't happen and I wouldn't lose half a day (or more) of my time trying to solve it if Spring was at the first place using SLF4J for instance.

                              Workaround I've used at the end is to throw away commons-logging.jar in favour of jcl104-over-slf4j.jar + slf4j-log4j12.jar (as log4j was used as a target logger).

                              Comment

                              Working...
                              X