tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From removeps-gro...@yahoo.com
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 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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message