tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject RE: How to have multiple loggers with shared code also using the logger?
Date Thu, 15 Jan 2009 05:01:16 GMT
> Because of the classloading hierarchy.  Once the logger is
> initialized with the common classloader, everybody uses that
> one.

Thanks.  I studied the Apache logger code.

When we call org.apache.log4j.Logger.getLogger(), it calls functions of LogManager.  The static
initializer block of LogManager gets using the thread's class loader, so
if the first webapp I run is mywebservice, then it will get from mywebservice,
such as mywebservice/WEB-INF/classes/  The root logger will be initialized
using this file, and all new loggers will inherit this configuration, which
does not seem very useful.

And since the log4j.jar resides in the ${catalina.home}/lib folder, this root logger is used
by all web apps.

So what I did is

(1) Create a in ${catalina.home}/lib/ or in a jar file here.

(2) This properties file should contain the configuration shared by all app loggers.  For
me, the file is one line:

(3) Rename in each webapp and swingapp and JUnit test app to

(4) Modify MyLog.getLogger(), which is a function in a jar file that is shared by all apps
(ie. a function in ${catalina.home}/lib) so that when a logger is created, initialize the
logger from the appropriate

import org.apache.log4j.PropertyConfigurator;

    * This function attempts to locate using the
    * thread's classloader, and returns a logger using the location of
    * as the logger name.
    * The logger will be initialized with the configuration in
    * This allows each application within the web server will use its own logger.
    * This function is thread-safe, and callers don't need to synchronized on MyLog.
    * @return
    * @throws NullPointerException if does not exist
   public static Logger getLogger()
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      URL log4j_properties = classLoader.getResource("");
      String loggerName = log4j_properties.toString();
      synchronized (MyLog.class)
         Logger logger = Logger.getRootLogger().getLoggerRepository().exists(loggerName);
         if (logger == null)
            logger = Logger.getLogger(loggerName);
            System.out.println("Created logger: loggerName=" + loggerName);
         return logger;

> Don't do that.  Keep just one copy of the source
> somewhere, just have your packaging script put the .class
> file in the webapp package.  No need to have an abstract
> class or subclasses.

Not sure if that would work as the log4j.jar is in ${catalina.home}/lib, so the root logger
is shared by all apps.

> > (1) Pass a logger from the webapp to the common code
> -- ie.
> > to add a Logger argument to all the functions in the
> common
> > code, but this sounds tedious.
> That's the cost of keeping things isolated, which is a
> worthwhile goal.
> > (2) In each webapp have a filter that sets a thread
> local
> > variable like ThreadLocal<Logger> threadLogger.
> Just make sure you clear the ThreadLocal on *every*
> possible exit path out of your request processing.  If you
> don't, you will have memory leaks in PermGen causing it
> to fill up as webapps are redeployed.

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message