> Also if you had one Tomcat Instances and 3 apps would they all share the one
> instance of Log4j and its static methods or would there be three instances
> of Log4j??
>

If you put Log4j in one of the parent classloaders that Tomcat makes available to webapps ( shared/lib, common/lib ) then That will be one instance of log4j serving many webapps. Actually, all webapps would use the same default logger repository or, hierarchy unless you do specifically create a new logger repository for each webapp using a custom logger repository selector. See the following doc on this:

http://qos.ch/containers/sc.html

I implemented a logger repository selector similar to the one described in that article called Log4jCRS. You can find it here:

http://barracuda.enhydra.org/software/cvs/cvsweb.cgi/Projects/EnhydraOrg/toolsTech/Barracuda/src/org/enhydra/barracuda/log4j/

It is used in both a Log4jInit servlet and a servlet context listener called Log4jApplicationWatch to initialize and shutdown loggers and appenders, respectively.

http://barracuda.enhydra.org/software/cvs/cvsweb.cgi/Projects/EnhydraOrg/toolsTech/Barracuda/src/org/enhydra/barracuda/webapp/log4j/


Log4jCRS needs to be in a classloader visible to log4j.jar. This means if Log4j.jar is in common/lib (where commons logging likes it to be) you can put Log4jCRS in shared/lib or common/lib. You can't put it in WEB-INF/lib of your app unless you also place a copy of log4j.jar there as well because Log4jCRS needs to talk to classes in Log4j.jar and vice-versa.

Log4jInit and Log4jApplicationWatch *must* be in WEB-INF/lib. This is because the custom logger repositories are keyed on each unique webapp classloader and so must be loaded in the webapp classloader of each individual application in order to support that condition.

You can store your log4j config file (properties or xml) in WEB-INF and provide something like the following to configure Log4jApplicationWatch and Log4jInit :


<!-- Shuts down all loggers and appenders at webapp shutdown -->
<listener>
<listener-class>
org.enhydra.barracuda.webapp.log4j.Log4jApplicationWatch
</listener-class>
</listener>


<!-- ============================================================== -->
<!-- Log4j declarations -->
<!-- ============================================================== -->
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>org.enhydra.barracuda.webapp.log4j.Log4jInit</servlet-class>
<init-param>
<!-- relative path to config file within current webapp -->
<param-name>log4j-config</param-name>
<param-value>WEB-INF/log4j.xml</param-value>
</init-param>
<init-param>
<!-- config file re-reading specified in milliseconds...
Note that if the webapp is served directly from the
.war file, configureAndWatch() cannot be used because
it requires a system file path. In that case, this
param will be ignored. Set to 0 or don't specify this
param to do a normal configure(). -->
<param-name>log4j-cron</param-name>
<param-value>5000</param-value>
</init-param>
<!-- optional param for use with a File Appender.
Specifies a path to be read from a log4j xml
config file as a system property. The property name is
dynamically generated and takes on the following pattern:
[webapp name].log.home
In Barracuda's case, it would be "Barracuda.log.home".
The path defaults to WEB-INF/logs directory, which is created
if it doesn't exist, unless the webapp is running directly
from a .war file.
Note that, if specified, the value is an absolute path, not
relative to the webapp. -->
<!-- <init-param>
<param-name>log4j-log-home</param-name>
<param-value>/usr/local/logs/tomcat</param-value>
</init-param> -->
<load-on-startup>1</load-on-startup>
</servlet>

And for logging to file, a system variable is automatically created by Log4jInit. The name is different for each webapp and predictable because it is based on the context name of the webapp. For instance, if I have a context with a path of "/Barracuda", then in my log4j.xml I use the variable ${Barracuda.log.home} to specify my filepath for a file appender such as:

<appender name="A2" class="org.apache.log4j.FileAppender">
<param name="File" value="${Barracuda.log.home}/main.log" />
<param name="Append" value="false" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n"/>
</layout>
</appender>

As you can see above in the configuratin for Log4jInit, there is a param you can set called "log4-log-home" where you can set any custom file path for the directory where the log file should exist. As is expained above, this defaults to WEB-INF/logs of your current webapp. Note that this assumes that the app is served out of a directory on the filesystem. If you serve your context directly from a .war file and you still want to use a file appender, you will want to set the "log4j-log-home" parameter to a place that you know exists as a directory on your filesystem.

That's about all the resources you need to use one instance of log4j.jar in common/lib and share it across all webapps without having each webapp's configuration interfere with any other webapp. Without Log4jCRS, all webapps in this case would run over each other because they would all use the same default logger repository. If you want to simplify things and not use Log4jCRS, then just make sure to put log4j.jar in every webapp's WEB-INF/lib directory. That will provide the same unique logging environment for each webapp as Log4jCRS provides, except you lose the advantage of sharing one instance of Log4j.

Jake

Reply via email to