This is one occasion when I hate to be right. Here is what I had to say about logging wrappers some time ago and was subsequently shouted down.
The following text appeared on a general@jakarta thread a few months ago. --------------------------------------------------------------------------------------------------- Given that log4j is such a low-level library, most organizations are suspicious to tie their code to log4j, especially considering the new logging API included in JDK 1.4. Before going onward, it is appropriate to mention that these two APIs are very similar. The classical usage pattern for log4j is: import org.apache.log4j.Logger; public class MyClass { final static Logger logger = Logger.getLogger("some.name"); public void foo1() { logger.debug("Hello world."); } public void foo2() { logger.info("Another message."); logger.error("Stop that!", new Exception("The earth is getting warmer.")); } } As you are well aware by now, one of the important benefits of log4j is that it can be configured at run time using configuration scripts. You can have hundreds or thousands of log statement but only one or two lines of Java code to configure log4j. The usage pattern for the JDK 1.4 logging API is: import java.util.logging.Logger; public class MyClass { final static Logger logger = Logger.getLogger("test"); public void foo1() { logger.debug("Hello world."); } public void foo2() { logger.info("Another message."); logger.error("Stop that!", new Exception("The earth is getting warmer.")); } } Notice anything similar? The JDK 1.4 logging API also supports configuration scripts. Being part of the JDK, may users reckon that the JSR47 API will supplant log4j some time in the near future. Surprisingly enough, it is not so easy to write a complete log-ging API. Users come to realize they need the features present in log4j but absent in JDK 1.4 logging. Moreover, log4j runs under JDK 1.1 or later whereas JDK 1.4 log-ging requires, well, JDK 1.4. Most users can't afford to tie their code to JDK 1.4. But they need logging and they need it now. A common strategy for protecting against future changes and at the same time to benefit from existing log4j features is to wrap log4j with a custom logging API. Log4j actually has support to facilitate such wrappers. It turns out that wrappers are not so trivial to write. I frequently receive email where a user runs into a problem with their wrapper and requests help. More often than not, these wrappers are of doubtful quality such that the cost of inactive (or disabled) log-ging statements is multiplied by a factor of 1'000 compared to direct log4j usage. The most common error in wrapper classes is the invocation of the Logger.getLogger method on each log request. This is guaranteed to wreak havoc on your application's performance. Of course, not all wrappers are of poor quality. For example, the commons-logging API is a prime example of a reasonable implementation. The commons-logging API will try to use different logging frameworks depending on their presence on the class path. See http://jakarta.apache.org/commons for more details. Obviously, even a good wrapper will carry a small overhead but that is not the point. The aspect where most users have difficulty is the initialization of the log4j API. Where should log4j.jar go? Where do I put the log4j.properties file? Can different web-applications have different log4j configurations? How do I initialize log4j in an application server? Although there is ample literature on the subject, much confusion re-mains. The commons-logging API supporting multiple logging frameworks has its own "discovery process" which is based on the resources available to a particular classloader. In addition, the commons-logging API will create its own logger wrapper for each of the classloaders in use within your application. Things were confusing before, they will be even more perplexing when commons-logging API enters widespread usage. With some effort, it might start making sense to you. Your users are unlikely to show the same perseverance or enthusiasm. Since the primary goal of the common-logging API is to discover and use the logging framework that is available at runtime, it can only cater for lowest common denominator of the different logging frameworks. As JDK 1.4 logging does not offer the same set of features as log4j, by using the common-logging API you would be missing those extra features, such as logging domains (an important feature planned for log4j 1.3), Nested Diagnostic Contexts (NDC) and Mapped Diagnostic Contexts (MDC) which are essential features in server-type applications. Unexpected interactions between log4j and a wrapper API are also quite probable. The developers of the wrapper will suspect a log4j problem and conversely the log4j developers will suspect a wrapper problem. By increasing the number of components required for logging the probability of bugs increases while the difficulty of resolving them increases by a higher factor. My main argument against wrappers is the increase in the complexity of the logging component. The justification for the existence of logging in the first place is to facilitate problem identification. As such, the logging component must be robust and simple to set up. The more complex the logging component gets the less useful it becomes. Logging is rarely the main focus of an application. Experience shows that if setting up logging involves many steps or consumes too much time software developers simply begin ignoring the logging component. Logging must be simple and apolitical. Regrettably, the current tendency is to complicate and politicize logging. Remember that the initial goal of introducing a wrapper API was to protect your coding investment. If for whatever reason you decide to drop log4j in favor of JDK 1.4 (or the other way around) a simple string search-and-replace operation will do. Most modern IDEs support search-and-replace operations on multiple files. At 11:54 11.07.2002 -0400, you wrote: >From: Ryan D. Cuprak > >Hello, > I recently downloaded Sun Microsystems webservices packet which came >with a jar "commons-logging.jar" which I think is a permutation of log4j >(possibly old) but not sure. Anyway, when I attempt to run my applet in a >browser I get the following exception trace (below) which I do not get if I >run the applet in my ide. Is org.apache.logging related to log4j? I >downloaded the latest log4 and it didn't look anything like the jar from >sun (contents). > >-Thanks, >Ryan Cuprak > >Exception: >java.lang.ExceptionInInitializerError: >org.apache.commons.logging.LogConfigurationException: >org.apache.commons.logging.LogConfigurationException: >java.lang.NullPointerException > > at > org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:494) > > at > org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:285) > > at > >com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnection.<clinit>(HttpSOAPConnection.java:37) > > at > >com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnectionFactory.createConnection(HttpSOAPConnectionFactory.java:25) > > at > com.kodak.sis.applet.UserList.UserListApplet.sendSOAPMessage(Unknown Source) > > at com.kodak.sis.applet.UserList.UserListApplet.start(Unknown Source) > > at sun.applet.AppletPanel.run(Unknown Source) > > at java.lang.Thread.run(Unknown Source) > >java.lang.ExceptionInInitializerError: >org.apache.commons.logging.LogConfigurationException: >org.apache.commons.logging.LogConfigurationException: >java.lang.NullPointerException > > at > org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:494) > > at > org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:285) > > at > >com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnection.<clinit>(HttpSOAPConnection.java:37) > > at > >com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnectionFactory.createConnection(HttpSOAPConnectionFactory.java:25) > > at > com.kodak.sis.applet.UserList.UserListApplet.sendSOAPMessage(Unknown Source) > > at com.kodak.sis.applet.UserList.UserListApplet.start(Unknown Source) > > at sun.applet.AppletPanel.run(Unknown Source) > > at java.lang.Thread.run(Unknown Source) -- Ceki -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>