Woodchuck,

The following web page describes this situation and a solution to the problem.
http://www.qos.ch/logging/sc.jsp

I have attached the solution that I created this week based on the information above. To compile you will need servlet-api.jar and log4j.jar to compile.

Include the jar you create from these files in your web application and then in your web.xml include the following sections.

This section can be used if your log4j.xml is not under /WEB-INF/log4j.xml
  <context-param>
    <param-name>log4jXmlLocation</param-name>
    <param-value>/WEB-INF/log4j.xml</param-value>
  </context-param>

The following calls invokes the listerner when the web app starts up to create a separate logging context for the web application.

  <listener>
    <listener-class>com.revolsys.logging.log4j.Log4jServletContextListener</listener-class>
  </listener>

Also make sure you have a listener that does the following when the context is destroyed otherwise you'll get a log of PermGen out of memory errors after a number of redeploys

        Introspector.flushCaches();
        LogFactory.getFactory().release();

Good luck,
Paul

On Wed, 2005-08-31 at 13:03 -0700, Woodchuck wrote:
hihi all,

on my TC 5.5.9 installation i deployed several web applications that
uses the default JCL logging.  that is, i placed a simple
logging.properties file into each web app's WEB-INF/classes folder and
i have per web app logging.  everything works beautifully.

then i installed a new web app that forced me to place
commons-logging.jar and log4j.jar into the ${Tomcat}/common/lib folder.
 as a result, all my previous per web app logging no longer works.

i believe this is because log4j was discovered in the
${Tomcat}/common/lib first, and therefore it has superceeded any other
logging system at the (lower) web app level.  this is due to Tomcat's
classloading process.

the reason this new web app required commons-logging.jar and log4j.jar
to be placed specifically into the ${Tomcat}/commons/lib folder is
because it instantiates a log4j logger object in it's start-up servlet
which extends HttpServlet which is found in the servlet-api.jar which
is also in the ${Tomcat}/commons/lib folder.  this is because Tomcat's
classloading hierarchy dictates that classes in the common/lib cannot
see web app classes 'downstream'.

does anyone have any suggestions on how i can have per web app logging
again?  i would like to keep my deployment process as web app isolated
as possible (ie. each web app deployed by WAR, drop it in and that's
it, no further steps necessary).

thanks in advance,
woodchuck


		
____________________________________________________
Start your day with Yahoo! - make it your home page 
http://www.yahoo.com/r/hs 


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

/*
 * Copyright 2005 Revolution Systems Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.revolsys.logging.log4j;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Hierarchy;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.RepositorySelector;
import org.apache.log4j.spi.RootCategory;

/**
 * The ContextClassLoaderRepositorySelector class is used to manage different
 * [EMAIL PROTECTED] LoggerRepository} heirarchies for different context class loaders. The
 * [EMAIL PROTECTED] #add()} method can be used to create a seperate logger repository for
 * the current thread context class loader. When the class loader is about to be
 * destroyed use the [EMAIL PROTECTED] #remove()} method to clean up the logger repository
 * for the class loader. See the [EMAIL PROTECTED] Log4jServletContextListener} for use in
 * web applications.
 * 
 * @author Paul Austin
 * @version 1.0
 */
public class ContextClassLoaderRepositorySelector implements RepositorySelector {
    /** The gaurd used to set the respository selector on the LogManager. */
    private static final Object GUARD = LogManager.getRootLogger();

    /** The map of class loaders to logging hierarchies. */
    private static final Map repositories = new HashMap();

    /**
     * The deault repository to use when one hasn't been created for the class
     * loader.
     */
    private static final LoggerRepository defaultRepository;

    static {
        defaultRepository = LogManager.getLoggerRepository();
        RepositorySelector selector = new ContextClassLoaderRepositorySelector();
        LogManager.setRepositorySelector(selector, GUARD);
    }

    /**
     * Get the logger repository for the current thread context class loader or
     * the default one if one does not exist.
     * 
     * @return The logger repository.
     */
    public final synchronized LoggerRepository getLoggerRepository() {
        Thread thread = Thread.currentThread();
        ClassLoader classLoader = thread.getContextClassLoader();
        Hierarchy hierarchy = (Hierarchy)repositories.get(classLoader);
        if (hierarchy == null) {
            return defaultRepository;
        } else {
            return hierarchy;
        }
    }

    /**
     * Add a new hierarchy for the current thread context class loader if one
     * does not exist or return the previous hierarchy.
     * 
     * @return The created heirarchy.
     */
    public static synchronized Hierarchy add() {
        Thread thread = Thread.currentThread();
        ClassLoader classLoader = thread.getContextClassLoader();
        return add(classLoader);
    }

    /**
     * Add a new hierarchy for the specified class loader if one does not exist
     * or return the previous hierarchy.
     * 
     * @param classLoader The classloader to create the hierarchy for.
     * @return The created heirarchy.
     */
    public static synchronized Hierarchy add(final ClassLoader classLoader) {
        Hierarchy hierarchy = (Hierarchy)repositories.get(classLoader);
        if (hierarchy == null) {
            hierarchy = new Hierarchy(new RootCategory((Level)Level.DEBUG));
            repositories.put(classLoader, hierarchy);
        }
        return hierarchy;
    }

    /**
     * Remove and shutdown the hierarchy for the current thread context class
     * loader class loader.
     */
    public static synchronized void remove() {
        Thread thread = Thread.currentThread();
        ClassLoader classLoader = thread.getContextClassLoader();
        remove(classLoader);
    }

    /**
     * Remove and shutdown the hierarchy for the specified class loader.
     * 
     * @param classLoader The classloader to create the hierarchy for.
     */
    public static synchronized void remove(final ClassLoader classLoader) {
        Hierarchy hierarchy = (Hierarchy)repositories.remove(classLoader);
        hierarchy.shutdown();
    }

}
/*
 * Copyright 2005 Revolution Systems Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.revolsys.logging.log4j;

import java.io.InputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Hierarchy;
import org.apache.log4j.xml.DOMConfigurator;

/**
 * The Log4jServletContextListener class uses the
 * [EMAIL PROTECTED] ContextClassLoaderRepositorySelector} to maintain a separate Log4j
 * configuration for a servlet context and to load the logging configuration
 * from the log4j.xml file specified by the log4jXmlLocation context-param (or
 * /WEB-INF/log4j.xml if not specified).
 * 
 * @author Paul Austin
 * @version 1.0
 */
public class Log4jServletContextListener implements ServletContextListener {
    /** The default location for the log4j.xml file. */
    public static final String DEFAULT_LOG4J_XML_LOCATION = "/WEB-INF/log4j.xml";

    /**
     * Initialize the logging for context by creating a new heirarchy for the
     * current thread context class context and loading the configuration from
     * the log4jXmlLocation context-param.
     * 
     * @param event The servler context event.
     */
    public void contextInitialized(ServletContextEvent event) {
        Hierarchy hierarchy = ContextClassLoaderRepositorySelector.add();
        ServletContext context = event.getServletContext();
        String log4jXml = context.getInitParameter("log4jXmlLocation");
        if (log4jXml == null) {
            log4jXml = DEFAULT_LOG4J_XML_LOCATION;
        }
        try {
            InputStream log4JConfig = context.getResourceAsStream(log4jXml);
            if (log4JConfig != null) {
                DOMConfigurator conf = new DOMConfigurator();
                conf.doConfigure(log4JConfig, hierarchy);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Clean up the context by removing the logging configuration for the
     * current context.
     * 
     * @param event The servler context event.
     */
    public void contextDestroyed(ServletContextEvent event) {
        ContextClassLoaderRepositorySelector.remove();
    }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to