RE: How to have multiple loggers with shared code also using the logger?
Here's an update on the logger issue. It too me long to figure out because I ran into an issue about privileged servlets and had to write my own log4j.properties parser. The original code posted earlier in this thread works in that it creates a different logger for web application, and allows the user to stop and restart the application. public static Logger getLogger() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); URL log4j_properties = classLoader.getResource(log4j_app.properties); String loggerName = log4j_properties.toString(); // throws NullPointerException if log4j_app.properties does not exist 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; } } One bug with the above is the line PropertyConfigurator.configure(log4j_properties); The above re-configures the root logger with the new log4j.properties, so basically the new configuration applies to all loggers. What would be nice is PropertyConfigurator.configure(logger, log4j_properties); that configures only the specified logger with the log4j_properties. Unfortunately, log4j does not have such a function, so I wrote my own (but it only supports the properties used in my log4j_app.properties files). Now, if web application 1 calls MyLog.getLogger() or calls common code that calls MyLog.getLogger() then the first logger will be used, and similarly for web application 2. Finally, I create a servlet import org.apache.catalina.manager.ManagerServlet; public class TomcatManagerServlet extends ManagerServlet The servlet is called for /reload, and it calls super.doGet() after doing some checks. It turns out that only privileged web applications can instantiate ManagerServlet, so one has to have the following in context.xml: Context privileged=true I'm not sure what is the practical impact of setting privileged=true, though the docs said something about the catalina and shared class loaders. So upon calling http://localhost/mywebservice/reload?path=/ the ROOT application is stopped and started. After the application restart, all users are logged out and they have to log in again, but the logger continues to work. A call to MyLog.getLogger() does not re-create the logger. The logger is really owned by the common code in ${catalina.home}/lib. The code URL log4j_properties = classLoader.getResource(log4j_app.properties); just gets the URL of the log4j.properties file. However, there is no pointer to anything in the webapp, so it's possible to stop the webapp. And the line PropertyConfigurator.configure(log4j_properties); opens the URL (by calling log4j_properties.getInputStream()), reads it, and closes it. So no stream in the webapp is open, and it's possible to stop the webapp. --- On Thu, 1/15/09, Caldarale, Charles R chuck.caldar...@unisys.com wrote: From: Caldarale, Charles R chuck.caldar...@unisys.com Subject: RE: How to have multiple loggers with shared code also using the logger? To: Tomcat Users List users@tomcat.apache.org Date: Thursday, January 15, 2009, 11:28 AM From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: RE: How to have multiple loggers with shared code also using the logger? How does one redploy a single application? Strange, I could not find any information on this seemingly basic task on google. Read the real docs first, then Google only if needed. http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#Deploying%20on%20a%20running%20Tomcat%20server http://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
Thanks, this makes sense. However, I'd like to find out what is being held onto by the log4j.jar. So I'd like to test it out. How does one redploy a single application? Strange, I could not find any information on this seemingly basic task on google. Thanks again. --- On Wed, 1/14/09, Caldarale, Charles R chuck.caldar...@unisys.com wrote: From: Caldarale, Charles R chuck.caldar...@unisys.com Subject: RE: How to have multiple loggers with shared code also using the logger? To: Tomcat Users List users@tomcat.apache.org Date: Wednesday, January 14, 2009, 9:27 PM From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: RE: How to have multiple loggers with shared code also using the logger? And since the log4j.jar resides in the ${catalina.home}/lib folder, this root logger is used by all web apps. The log4j.jar is only there because you put it there. It does not come with the Tomcat distribution, and it's normally placed in the WEB-INF/lib directory of each webapp that needs it. By having such a jar in a common location, you've pretty much guaranteed that you'll have to take Tomcat down to redeploy a single webapp - the old webapp won't go away because log4j will be hanging onto references to it. (A common cause of PermGen filling up after redeployments.) The servlet spec (and experience) strongly suggest that webapps be kept as isolated as possible for this kind of reason. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: RE: How to have multiple loggers with shared code also using the logger? How does one redploy a single application? Strange, I could not find any information on this seemingly basic task on google. Read the real docs first, then Google only if needed. http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#Deploying%20on%20a%20running%20Tomcat%20server http://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
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 ThreadLocalLogger 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
RE: How to have multiple loggers with shared code also using the logger?
From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: RE: How to have multiple loggers with shared code also using the logger? And since the log4j.jar resides in the ${catalina.home}/lib folder, this root logger is used by all web apps. The log4j.jar is only there because you put it there. It does not come with the Tomcat distribution, and it's normally placed in the WEB-INF/lib directory of each webapp that needs it. By having such a jar in a common location, you've pretty much guaranteed that you'll have to take Tomcat down to redeploy a single webapp - the old webapp won't go away because log4j will be hanging onto references to it. (A common cause of PermGen filling up after redeployments.) The servlet spec (and experience) strongly suggest that webapps be kept as isolated as possible for this kind of reason. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
-Original Message- From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] How to have multiple loggers with shared code also using the logger? This is more of a log4j question that a Tomcat one. From a brief look at the log4j sources it looks as if you'll need a custom RepositorySelector that used the context classloader to select the repository to use. I thought log4j did that by default. I could be wrong on that or I might have read the source code incorrectly. Mark - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: How to have multiple loggers with shared code also using the logger? How to have multiple loggers with shared code also using the logger? In ${catalina.home}/lib there is a jar file that contains class MyLog. Doctor, doctor, it hurts when I do this. The simple fix is: don't do it. Package your webapps so that each contains a copy of MyLog rather than putting that class in the common location. You can still maintain the same source, just make sure the .class file is located locally in each webapp that uses it. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
Why is it what I'm trying to do not working though? It seems that my MyLog.getLogger function does find the correct logger name, and that Logger.getLogger() is always using the the first log4j.properties that was found. Yeah, I had tried something like this, namely to have a class AbstractMyLog in the common folder, and a class MyLog in each of the webapps that derives from AbstractMyLog so as to minimize code changes. But then the common code also needs to write to the log file, and it should use the log file of the web application that called it. The other ideas I had are: (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. (2) In each webapp have a filter that sets a thread local variable like ThreadLocalLogger threadLogger. --- On Tue, 1/13/09, Caldarale, Charles R chuck.caldar...@unisys.com wrote: From: Caldarale, Charles R chuck.caldar...@unisys.com Subject: RE: How to have multiple loggers with shared code also using the logger? To: Tomcat Users List users@tomcat.apache.org Date: Tuesday, January 13, 2009, 6:21 AM From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: How to have multiple loggers with shared code also using the logger? How to have multiple loggers with shared code also using the logger? In ${catalina.home}/lib there is a jar file that contains class MyLog. Doctor, doctor, it hurts when I do this. The simple fix is: don't do it. Package your webapps so that each contains a copy of MyLog rather than putting that class in the common location. You can still maintain the same source, just make sure the .class file is located locally in each webapp that uses it. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: How to have multiple loggers with shared code also using the logger?
From: removeps-gro...@yahoo.com [mailto:removeps-gro...@yahoo.com] Subject: RE: How to have multiple loggers with shared code also using the logger? Why is it what I'm trying to do not working though? It seems that my MyLog.getLogger function does find the correct logger name, and that Logger.getLogger() is always using the the first log4j.properties that was found. Because of the classloading hierarchy. Once the logger is initialized with the common classloader, everybody uses that one. Yeah, I had tried something like this, namely to have a class AbstractMyLog in the common folder, and a class MyLog in each of the webapps that derives from AbstractMyLog so as to minimize code changes. 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. (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 ThreadLocalLogger 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. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org