> 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 log4j.properties 
using the thread's class loader, so if the first webapp I run is mywebservice, 
then it will get log4j.properties from mywebservice, such as 
mywebservice/WEB-INF/classes/log4j.properties.  The root logger will be 
initialized using this log4j.properties 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 log4j.properties in ${catalina.home}/lib/log4j.properties 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:
log4j.rootLogger=warn

(3) Rename log4j.properties in each webapp and swingapp and JUnit test app to 
log4j_app.properties.

(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 log4j_app.properties.

import org.apache.log4j.PropertyConfigurator;

   /**
    * This function attempts to locate log4j_app.properties using the
    * thread's classloader, and returns a logger using the location of
    * log4j_app.properties as the logger name.
    * The logger will be initialized with the configuration in 
log4j_app.properties.
    * 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 log4j_app.properties does not exist
    */
   public static Logger getLogger()
   {
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      URL log4j_properties = classLoader.getResource("log4j_app.properties");
      String loggerName = log4j_properties.toString();
      synchronized (MyLog.class)
      {
         Logger logger = 
Logger.getRootLogger().getLoggerRepository().exists(loggerName);
         if (logger == null)
         {
            logger = Logger.getLogger(loggerName);
            PropertyConfigurator.configure(log4j_properties);
            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: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to