[slf4j-user] Per Web App logging

Amir Mistric amistric at nemours.org
Thu Nov 23 22:01:54 CET 2006


Well I tried passing in the "whole" ServletContext and that worked fine...
I deployed several web apps and they each had a separate logging context... 
I am not sure if this approach would suffer from the same problems as
ClassLoader approach though.

I am just wondering if there is an easier way for an web app to have its own
logging setup.



Below is the whole class and after it, the class that calls it
----------------------------------------------------------------
public final class Log4JWebContextRS implements RepositorySelector {

    private LoggerRepository                defaultRepository;
    private Map<ServletContext, Hierarchy>  repositories    = new
HashMap<ServletContext, Hierarchy>();
    private ServletContext                  currentContext  = null;
    private String                          log4JConfFile   = null;
    private static final String             log4jInitParam =
"log4j.config.file";

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.log4j.spi.RepositorySelector#getLoggerRepository()
     */
    public LoggerRepository getLoggerRepository() {
        LoggerRepository repository = (LoggerRepository)
repositories.get(this.currentContext);
        if (repository == null) {
            return defaultRepository;
        } else {
            return repository;
        }
    }

    // private constructor to prevent instantiation
    public Log4JWebContextRS(final ServletContext context) {
        this.currentContext = context;
        this.defaultRepository = LogManager.getLoggerRepository();
        String log4jConfig =
this.currentContext.getInitParameter(Log4JWebContextRS.log4jInitParam);
        if (log4jConfig == null) {
            this.log4JConfFile = "log4j.xml";
        } else {
            this.log4JConfFile = this.currentContext.getRealPath("/") +
log4jConfig;
        }
        
        Hierarchy hierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
        configureLog4J(log4JConfFile, hierarchy);
        repositories.put(context, hierarchy);        
    }

    // configure Log4J using XML or Properties file
    private void configureLog4J(String log4jConf, Hierarchy hierarchy) {
        try {
            if (log4jConf.endsWith(".properties")) {
                PropertyConfigurator propConf = new PropertyConfigurator();
                propConf.doConfigure(log4jConf, hierarchy);
                System.out.println("Log4J PropertyConfigurator:" +
log4jConf);
            } else if (log4jConf.endsWith(".xml")) {
                DOMConfigurator conf = new DOMConfigurator();
                conf.doConfigure(log4jConf, hierarchy);
                System.out.println("Log4J DOMConfigurator:" + log4jConf);
            } else {
                throw new Exception("Please use either '.properties' or
'.xml' file extensions for Log4J configuration files");
            }
        } catch (IOException e) {
            System.out.println("I/O exception occured while accessing" +
log4jConf);
            e.printStackTrace();
        } catch (SAXException e) {
            System.out.println("SAX parsing exception occured while
accessing" + log4jConf);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}// end of Log4JWebContextRS
-------------------------------------------------------
public final class MyWebAppContextListener implements ServletContextListener
{

    private String log4jConfig = null;
    private ServletContext context = null;
    // we cannot use Logger.getLogger until we initialize it...
    private static Logger  log;

    /**
     * @param pServletContextEvent The servlet context event
     */
    public void contextInitialized(final ServletContextEvent
pServletContextEvent) {
        context = pServletContextEvent.getServletContext();
        log4jConfig = this.context.getRealPath("/") +
this.context.getInitParameter("log4j.config.file");
    
        //1. using class loader
        Log4JClassLoaderRS.addToRepository(log4jConfig);
        
        //2. using JNDI
        //RepositorySelector theSelector = new Log4jJndiRS(log4jConfig);
        
        //3. using ServletContext
        RepositorySelector theSelector = new Log4JWebContextRS(context);
        //LogManager.setRepositorySelector(theSelector,
LogManager.getRootLogger());
        
        
        // assign a logger
        MyWebAppContextListener.log =
Logger.getLogger(MyWebAppContextListener.class);
        // do some logging...
 
log.info("-----------------------------------------------------------");
        log.info("Initializing context: " +
context.getServletContextName());  
    }

    /**
     * @param pServletContextEvent The servlet context event
     */
    public void contextDestroyed(final ServletContextEvent
pServletContextEvent) {
        context = pServletContextEvent.getServletContext();
        log.info("Destroying context: " + context.getServletContextName());
 
log.info("-----------------------------------------------------------");
        // we have to remove the Log4J config for this webapp from
repository
        //Log4JClassLoaderRS.removeFromRepository();
        context = null;
    }
}


-----------------------------------------------------------


-----Original Message-----
From: user-bounces at slf4j.org [mailto:user-bounces at slf4j.org] On Behalf Of
Ceki Gülcü
Sent: Wednesday, November 22, 2006 5:05 PM
To: User list for the slf4j project
Subject: Re: [slf4j-user] Per Web App logging


How would the logger factory know in which context you are? (It won't have 
access to any of HttpRequest/HttpRespons/Session/Servlet/etc.)

At 10:16 PM 11/22/2006, you wrote:
>That is an excellent point....
>But is there anything else that can be used as a key that would reduce the
>"complexity". Is all we care about a unique key to logging context name?
>
>         h = new Hierarchy(new RootCategory(Level.DEBUG));
>         ht.put(loggingContextName, h);
>
>
>If so can we use something like context.getServletContextName();
>This returns a string and I can capture it when app starts and pass it onto
>RepositorySelector....
>
>
>---javadoc----
>getServletContextName
>
>public java.lang.String getServletContextName()
>
>     Returns the name of this web application corresponding to this
>ServletContext as specified in the deployment descriptor for this web
>application by the display-name element.
>
>     Returns:
>         The name of the web application or null if no name has been
declared
>in the deployment descriptor.
>     Since:
>         Servlet 2.3
>---javadoc----
>
>
>
>Again, thanks a lot for your responses...
>
>
>Regards
>Amir
>
>
>
>
>
>-----Original Message-----
>From: user-bounces at slf4j.org [mailto:user-bounces at slf4j.org] On Behalf Of
>Ceki Gülcü
>Sent: Wednesday, November 22, 2006 4:07 PM
>To: User list for the slf4j project; 'User list for the slf4j project'
>Subject: Re: [slf4j-user] Per Web App logging
>
>Amir,
>
>Holding classloaders references as keys in a map that is references by a
>class located at the server level, will prevent your application from being
>garbage collected. There is no such problem with String references which
>the JNDI approach uses.
>
>HTH,
>
>At 10:59 PM 11/21/2006, Amir Mistric wrote:
> >Ceki
> >
> >After sending you the whole class (previous email) I looked over its code
> >again and I also looked over this url. http://www.qos.ch/logging/sc.jsp
> >
> >The only significant difference I saw was that hashtable (or a hashmap in
>my
> >case) was using a different key approach. In Log4JloggingRepository class
> >the key is the Thread.currentThread().getContextClassLoader() while in
> >JNDIRS is the JNDI env key. JNDIRS also doesn't have a way to pass in
>config
> >file but other than that why would JNDI approach be more portable than
> >http://wiki.jboss.org/wiki/Wiki.jsp?page=Log4jRepositorySelector ?
> >
> >Regards
> >Amir
> >
> >
> >
> >-----Original Message-----
> >From: user-bounces at slf4j.org [mailto:user-bounces at slf4j.org] On Behalf Of
> >Ceki Gülcü
> >Sent: Monday, November 20, 2006 5:21 PM
> >To: User list for the slf4j project
> >Subject: Re: [slf4j-user] Per Web App logging
> >
> >
> >
> >In the MyWebAppContextListener  code you supplied, one can read:
> >
> >   Log4JContextualRepositorySelector.addToRepository(pConfigFilePath);
> >
> >How is the addToRepository method defined?
> >
> >At 11:14 PM 11/20/2006, you wrote:
> > >Yes it is and all we did was to rename the MyRepositorySelector class
>that
> > >JBoss Wiki has. The code is the same as on
> > >http://wiki.jboss.org/wiki/Wiki.jsp?page=Log4jRepositorySelector
> > >
> > >Amir
> > >
> > >-----Original Message-----
> > >From: user-bounces at slf4j.org [mailto:user-bounces at slf4j.org] On Behalf
Of
> > >Ceki Gülcü
> > >Sent: Monday, November 20, 2006 4:51 PM
> > >To: User list for the slf4j project
> > >Subject: Re: [slf4j-user] Per Web App logging
> > >
> > >
> > >Hi Amir,
> > >
> > >Is the Log4JContextualRepositorySelector class yours?
> > >
> > >At 09:55 PM 11/20/2006, you wrote:
> > > >Hi Ceki
> > > >
> > > >Thanks for the quick reply.
> > > >Here are my answers:
> > > >
> > > > >If you use the JNDI-based repository selector, you can place a
single
> > > > >log4j.jar in the containers shared class loader. I am a little
> >surprised
> > > > >that you need to copy log4j.jar in each web-app. Can you please
> > >elaborate?
> > > >
> > > >Here is the URL we used to configure the RepositorySelector.
> > > >http://wiki.jboss.org/wiki/Wiki.jsp?page=Log4jRepositorySelector
> > > >We have about 10 web apps running on JBoss AS and the above solution
> >works.
> > > >Each web app has its own WEB-INF/lib/log4j.jar and
WEB-INF/log4j.xml...
> > > >Also, each application has a class that implements
> >ServletContextListener.
> > > >
> > > >public final class MyWebAppContextListener implements
> > >ServletContextListener
> > > >{
> > > >
> > > >     private ServletContext context = null;
> > > >     // we cannot use Logger.getLogger until we initialize it...
> > > >     private static Logger  log;
> > > >
> > > >...
> > > >...
> > > >...
> > > >
> > > >In this class we call (in contextInitialized() method):
> > > >
> > > >         this.context.log("Initializing Log4J...");
> > > >         // Before using Log4J logging system, we must initialize it
by
> > > >adding
> > > >         // the webapp specific configuration to the repository.
> > > >
> > >Log4JContextualRepositorySelector.addToRepository(pConfigFilePath);
> > > >         // note that we can't call Logger.getLogger() until
> > > >         // Log4JContextualRepositorySelector.addToRepository() is
> >called.
> > > >         // For all other classes in the webapp, you can call
> > > >Logger.getLogger()
> > > >         // at any time.
> > > >         log = Logger.getLogger(FindADocContextListener.class);
> > > >
> > > >That is it....
> > > >However this fails if we remove log4j.jar from WEB-INF/lib...
> > > >
> > > >
> > > >I do apologize if this question is gettting off topic
> > > >
> > > >Amir
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >-----Original Message-----
> > > >From: user-bounces at slf4j.org [mailto:user-bounces at slf4j.org] On
Behalf
>Of
> > > >Ceki Gülcü
> > > >Sent: Monday, November 20, 2006 3:43 PM
> > > >To: User list for the slf4j project
> > > >Subject: Re: [slf4j-user] Per Web App logging
> > > >
> > > >Hi Amir,
> > > >
> > > >At 09:32 PM 11/20/2006, Amir Mistric wrote:
> > > > >Hello Everyone
> > > > >
> > > > >My company would like to try SLF4J as a replacement for Log4J.
> > > > >Currently we use JBoss AS 4.x and the problem we had was that we
>could
> > >not
> > > > >configure logging "per web application".
> > > > >We ended up using RepositorySelector trick in order to be able to
>have
> >a
> > > > >separate log4j.xml in every web application deployed.
> > > > >This approach, however, requires each web app to have a copy of
> >log4j.jar
> > > > >in its WEB-INF/lib......
> > > >
> > > >If you use the JNDI-based repository selector, you can place a single
> > > >log4j.jar in the containers shared class loader. I am a little
>surprised
> > > >that you need to copy log4j.jar in each web-app. Can you please
> >elaborate?
> > > >
> > > > >Recently we decided to create a shared library repository for all
web
> > >apps
> > > > >we have.
> > > > >While this approach has reduced the "baggage" each web app had in
its
> > > > >WEB-INF/lib we still have to use log4j.jar ....
> > > > >
> > > > >Our goal is simple. Have every web application running on the same
>app
> > > > >server have its own logging config file but share the single JAR
(or
> > >jars).
> > > >
> > > >Not yet, but it's core feature planned in one of the next releases of
> > > >logback.
> > > >
> > > > >Can SLF4J accomplish this (using built in logback classic) for us?
> > > >
> > > >No, SLF4J is just a front for logback/jul/log4j/jcl. While SLF4J
cannot
> > > >accomplish what you are asking, log4j can do so, and logback will in
>the
> > > >near future.
> > > >
> > > > >Thanks
> > > > >Amir
> > > >
> > > >--
> > > >Ceki Gülcü
> > > >Logback: The reliable, generic, fast and flexible logging framework
for
> > > >Java.
> > > >http://logback.qos.ch
> > > >
> > > >_______________________________________________
> > > >user mailing list
> > > >user at slf4j.org
> > > >http://www.slf4j.org/mailman/listinfo/user
> > > >
> > > >_______________________________________________
> > > >user mailing list
> > > >user at slf4j.org
> > > >http://www.slf4j.org/mailman/listinfo/user
> > >
> > >--
> > >Ceki Gülcü
> > >Logback: The reliable, generic, fast and flexible logging framework for
> > >Java.
> > >http://logback.qos.ch
> > >
> > >_______________________________________________
> > >user mailing list
> > >user at slf4j.org
> > >http://www.slf4j.org/mailman/listinfo/user
> > >
> > >_______________________________________________
> > >user mailing list
> > >user at slf4j.org
> > >http://www.slf4j.org/mailman/listinfo/user
> >
> >--
> >Ceki Gülcü
> >Logback: The reliable, generic, fast and flexible logging framework for
> >Java.
> >http://logback.qos.ch
> >
> >_______________________________________________
> >user mailing list
> >user at slf4j.org
> >http://www.slf4j.org/mailman/listinfo/user
> >
> >_______________________________________________
> >user mailing list
> >user at slf4j.org
> >http://www.slf4j.org/mailman/listinfo/user
>
>--
>Ceki Gülcü
>Logback: The reliable, generic, fast and flexible logging framework for
>Java.
>http://logback.qos.ch
>
>_______________________________________________
>user mailing list
>user at slf4j.org
>http://www.slf4j.org/mailman/listinfo/user
>
>_______________________________________________
>user mailing list
>user at slf4j.org
>http://www.slf4j.org/mailman/listinfo/user

-- 
Ceki Gülcü
Logback: The reliable, generic, fast and flexible logging framework for
Java.
http://logback.qos.ch

_______________________________________________
user mailing list
user at slf4j.org
http://www.slf4j.org/mailman/listinfo/user




More information about the slf4j-user mailing list