Re: Question re: JBoss / Log4J / RepositorySelector / Web-apps
Hi all, I'm trying to work with JBoss and Log4J, and have run into a question that I can't seem to find the answer to. In the course of trying to figure out how to specify per-application Log4J configuration for web-apps running under JBoss, I found this reference to the RepositorySelector mechanism: https://www.qos.ch/logging/sc.html What I don't know however is: 1. Does JBoss even support this mechanism? Is JBoss written in Java? Yes, I think it is. Yep, it is supported. Repository selectors just need some unique characteristic that can differentiate logger repositories. There are a couple of different obvious choices to use. One is keying on different classloaders. The other, under a J2EE environment, is keying on a JNDI namespace. Obviously, both of these can be used in JBoss since it uses classloaders and is a J2EE container. Sorry, I should have worded my question a little better. What I meant was more like Does JBoss directly support this, via providing a relevant RepositorySelector class, and does it set a RepositorySelector when it initializes Log4J? Or something along those lines. Based on some reading I'd done, I was under the impression that setting a RepositorySelector had to be done by the container, when operating in a container environment. If it is the case that the container does not have to set the RespositorySelector in order to use this approach, would that not mean however, that my client code would have to call setRepositorySelector()? 2. If so, how do I utilize it in my client code, to retrieve the app specific Log4J instance? My initial thought, based on a quick perusal of the javadoc gives me the idea I'd need something like this: public class ControllerServlet { private static Logger logger; private ServletConfig config; public void init(ServletConfig config ) throws ServletException { this.config = config; LoggerRepository repos = LogManager.getLoggerRepository(); logger = repos.getLogger( (ControllerServlet.class ).toString()); } snip } is this anything close to correct? It is actually easier than that. Your logger code doesn't need to change at all. Just. Once the logger repository selector is used in the initialization of Log4j, you will be using a unique logger repository. Aaah, that's the catch... do you have any idea how, in the JBoss environment, to ensure that the correct RepositorySelector class is used when Log4J is initialized? That seems to be the major thing I'm not understanding here... If JBoss initializes Log4J itself, wouldn't that prevent me from being able to modify the selector? Or am I missing something badly here? 3. assuming the above (or something similar) is used to retrieve the app specific instance of Log4J, is there anything special I need to do to tell Log4J where to find the app-specific log4j.xml? Or is simply putting log4j.xml under WEB-INF/classes sufficent? Would I still need to call DOMConfigurator.configure()? If you use the default initialization mechanism, you will be logging in the default logger repository. If you put both log4j.jar and your log4j.xml in the webapp's WEB-INF/lib and WEB-INF/classes, then you should be able to use this mechanism since the servlet spec makes it so that the webapp class loader is checked first for classes and resources. Only after that does it check parent classloader. Note that this is converse to the normal Java2 class loader hierarchy. If you put log4j.jar in a parent classloader (outside of WEB-INF/lib), however, you will need to use a repository selector to keep your logging separated from other apps. Hmm... so are you saying that if I put log4j.jar in WEB-INF/lib, since the class-loader for my web-app will look there first, it doesn't matter that JBoss has already initialized an instance of Log4J (presumably in a separate class-loader)? If so, this starts to make a little bit more sense. I thought I read something on the 'net somewhere, though, which indicated that putting log4j.jar in WEB-INF/lib was a bad idea, which is why I've been thinking pretty much exclusively in terms of relying on the Log4J instance loaded by JBoss's boot process. 4. is there any configuration at the JBoss level that needs to be done to support app-specific Log4J instances? I know about the log4.xml under server/default/conf/ which specifies the global Log4J properties for the container itself... it wouldn't need to be touched for this would it? Not entirely sure about JBoss specifics, but if you put log4j.jar in WEB-INF/lib, that jar will be loaded by the webapp rather than the jar provided by the global JBoss classloader (although I'm not totally sure about JBoss' single classloader scheme, but it seems that would violate the servlet spec if they didn't allow for a separate webapp class loader). However, if you want to use the global log4j.jar and use separate logger repositories,
Re: Question re: JBoss / Log4J / RepositorySelector / Web-apps
At 09:00 PM 8/23/2003 -0400, you wrote: Hi all, I'm trying to work with JBoss and Log4J, and have run into a question that I can't seem to find the answer to. In the course of trying to figure out how to specify per-application Log4J configuration for web-apps running under JBoss, I found this reference to the RepositorySelector mechanism: https://www.qos.ch/logging/sc.html What I don't know however is: 1. Does JBoss even support this mechanism? Is JBoss written in Java? Yes, I think it is. Yep, it is supported. Repository selectors just need some unique characteristic that can differentiate logger repositories. There are a couple of different obvious choices to use. One is keying on different classloaders. The other, under a J2EE environment, is keying on a JNDI namespace. Obviously, both of these can be used in JBoss since it uses classloaders and is a J2EE container. Sorry, I should have worded my question a little better. What I meant was more like Does JBoss directly support this, via providing a relevant RepositorySelector class, and does it set a RepositorySelector when it initializes Log4J? Or something along those lines. Based on some reading I'd done, I was under the impression that setting a RepositorySelector had to be done by the container, when operating in a container environment. That is normally the caseand I'm not sure if JBoss has implemented this or not. You'll probably find out more info on their list. The way I have things set up in my repository selectors and my InitContextListener get around this limitation. Of course, the caveat is that the first application to use a repostiory selector forces that selector on all other appsat least if those apps are using the same instance of Log4j (from a parent classloader instead of the webapp class loader). To see a case where the container takes care of this, see the experimental Log4jHelper addon application for Tomcat-3.3.x... http://cvs.apache.org/viewcvs/jakarta-tomcat/proposals/Log4jHelper/ If it is the case that the container does not have to set the RespositorySelector in order to use this approach, would that not mean however, that my client code would have to call setRepositorySelector()? Yep, in your initialization. See my InitContextListener for an example. 2. If so, how do I utilize it in my client code, to retrieve the app specific Log4J instance? My initial thought, based on a quick perusal of the javadoc gives me the idea I'd need something like this: public class ControllerServlet { private static Logger logger; private ServletConfig config; public void init(ServletConfig config ) throws ServletException { this.config = config; LoggerRepository repos = LogManager.getLoggerRepository(); logger = repos.getLogger( (ControllerServlet.class ).toString()); } snip } is this anything close to correct? It is actually easier than that. Your logger code doesn't need to change at all. Just. Once the logger repository selector is used in the initialization of Log4j, you will be using a unique logger repository. Aaah, that's the catch... do you have any idea how, in the JBoss environment, to ensure that the correct RepositorySelector class is used when Log4J is initialized? That seems to be the major thing I'm not understanding here... If JBoss initializes Log4J itself, wouldn't that prevent me from being able to modify the selector? Or am I missing something badly here? Yes, probably so, since you would need to have a handle on the original guard object that was used when setting the repository selector. Without that, further calls to LogManager.setRepositorySelector() will fail to set your preferred selector. But that isn't a problem if the existing selector works for you. There isn't any reason it shouldn't. 3. assuming the above (or something similar) is used to retrieve the app specific instance of Log4J, is there anything special I need to do to tell Log4J where to find the app-specific log4j.xml? Or is simply putting log4j.xml under WEB-INF/classes sufficent? Would I still need to call DOMConfigurator.configure()? If you use the default initialization mechanism, you will be logging in the default logger repository. If you put both log4j.jar and your log4j.xml in the webapp's WEB-INF/lib and WEB-INF/classes, then you should be able to use this mechanism since the servlet spec makes it so that the webapp class loader is checked first for classes and resources. Only after that does it check parent classloader. Note that this is converse to the normal Java2 class loader hierarchy. If you put log4j.jar in a parent classloader (outside of WEB-INF/lib), however, you will need to use a repository selector to keep your logging separated from other apps. Hmm... so are you saying that if I put log4j.jar in WEB-INF/lib, since the class-loader for my web-app will look there first, it doesn't matter