Hi Dave,

Thank you for bringing this subject up.

On Thu, 12 May 2022 at 13:16, Dave Piper (HE/HIM)
<davepi...@microsoft.com.invalid> wrote:

> We've been using log4j for over a decade to produce logs for various
> webapps within a single tomcat instance. Some of our loggers and file
> appenders are defined within the tomcat/lib folder itself so that they're
> picked up by the common classloader and can be shared by multiple webapps.
> The intention of this was to remove the risk of separate webapp processes
> writing to the same file simultaneously and causing write issues. We also
> have per-webapp log4j config.
>
> Our file system is laid out as follows:
>
> - tomcat
> - tomcat/lib/log4j2.xml   (defines shared appenders and loggers)
> - tomcat/lib/log4j-core.jar (and other log4j jars)
> - ...
> - tomcat/webapps/mywebapp1/WEB-INF/classes/log4j2.xml  (defines appenders
> and loggers for webapp 1)
> - tomcat/webapps/mywebapp1/WEB-INF/lib/log4j-core.jar  (and other log4j
> jars)
> - ...
> - tomcat/webapps/mywebapp2/WEB-INF/classes/log4j2.xml  (defines appenders
> and loggers for webapp 2)
> - tomcat/webapps/mywebapp2/WEB-INF/lib/log4j-core.jar   (and other log4j
> jars)
> - ...
>

Can you explain in more detail your previous Log4j 1.x setup? If it was
similar to what you present here, I fail to understand how could you have a
shared set of appender instances (not appender identically configured).

This was working as designed when we were using tomcat 8 and log4j v1, but
> since moving to tomcat 9 and log4j v2 we're no longer able to load both
> config files. When log4j logging is set to debug in tomcat, catalina.out
> shows that tomcat discovers and processes the webapp-specific log4j2.xml
> files but not the one under log4j2.xml.  We can configure tomcat / log4j so
> that each webapp loads multiple config files, but we think it's only
> loading those on a per-webapp basis, I think it's not loading one shared
> XML file so we don't get shared appenders. Having log4j v2 jars in multiple
> locations is also causing various errors.
>

Due to the way classloader delegation works in servlet containers, if an
application has a copy of `log4j-api` and `log4j-core`, it can not use the
copy from the common classloader. As you remarked yourself, you can share
the configuration file, but this will just create multiple identically
configured file appenders.

In order to have a set of common appenders you need to:

1. Change the delegation model of each web application classloader to
delegate to the parent first. You can do this by adding to
`$CATALINA_BASE/conf/context.xml`:

    <Loader delegate="true" />

   After this change you should be careful what you put in
`$CATALINA_BASE/lib`, since it will be shared by all applications.

 2. Configure Log4j2 to read both `log4j2.xml` files. This can be done
using the `log4j2.configurationFile` setting. For example a
`-Dlog4j2.configurationFile=${sys:catalina.base}/lib/log4j2.xml,classpath:log4j2.xml`
should work, although I would rather rename the shared configuration file.

After these changes:
 * each application will use the same copy of `log4j-core`,
 * since the default `ContextSelector` is `ClassLoaderContextSelector`,
each application will have its own logger context and configuration,
 * technically each application will have its own set of appenders, but the
`FileManager`s will be shared by all applications. Therefore each log file
will be opened only once regardless of the number of applications that use
it.

Piotr

Reply via email to