Piers,

I've configured two webapps with the log4j2 configuration outside of the
*war files. The approach I'll describe is working in Tomcat 8.5 and Tomcat
9.

First I create a LogListener class for the webapp:

public class LogListener implements ServletContextListener {

  private static final Logger LOGGER = LogManager.getLogger();
  private Log4jServletContextListener listener = new
Log4jServletContextListener();

  @Override
  public void contextDestroyed(ServletContextEvent event) {
    listener.contextDestroyed(event);
  }


  @Override
  public void contextInitialized(ServletContextEvent event) {
    String loggerPath = "WEB-INF/classes/log4j2.xml";

    ServletContext context = event.getServletContext();
    String fileString = context.getInitParameter("log4jConfiguration");
    if (fileString != null && fileString.length() > 0
        && !fileString.equals("*")) {
      if ((new File(fileString)).exists()) {
        loggerPath = fileString;
      }
    }
    event.getServletContext().setInitParameter(
      Log4jWebSupport.LOG4J_CONFIG_LOCATION, loggerPath);
    listener.contextInitialized(event);
    LOGGER.info("logging properties from " + loggerPath);
  }
}


I declare the LogListener in web.xml and add some filtering:

  <listener>
    <!-- This listener *must* be first for log4j to work. -->

<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
  </listener>
  <listener>
    <!-- This listener is required to set the log4jConfiguration fallback.
-->

<listener-class>com.mycorp.server.rest.listeners.LogListener</listener-class>
  </listener>

  <!-- See https://logging.apache.org/log4j/2.x/manual/webapp.html -->
  <filter>
    <filter-name>log4jServletFilter</filter-name>

<filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>log4jServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
    <dispatcher>ASYNC</dispatcher>
  </filter-mapping>

  <context-param>
    <param-name>isLog4jAutoInitializationDisabled</param-name>
    <param-value>true</param-value>
  </context-param>

Finally, in the Tomcat context file, META-INF/context.xml, I add the
log4jConfiguration that LogListener wants:

<Parameter description="Configure Log4j2 logging."
name="log4jConfiguration" override="false"
value="/Users/admin/local/etc/my_logger.xml"/>


When I start Tomcat, the first entry in the log is

12:23:23.439 INFO  LogListener.contextInitialized() - logging properties
from /Users/admin/local/etc/my_logger.xml

At one time I had this working in Jetty, but I no longer remember where to
set its context.

We've installed these apps on numerous servers, both Linux (of various
distros) and macOS. AFAIK, they're also running on a number of Windows
servers as well. Logging works everywhere.

On Wed, Mar 20, 2024 at 12:09 PM Piers Uso Walter <piers.wal...@ilink.de>
wrote:

> Hi Piotr,
>
> Thanks for your email.
>
> Here is what I’m trying to do:
> The previous version of our app stores the log4j configuration within the
> war file.
> This works fine but is annoying if one wants to change any logging setting
> (unpacking the war, changing the configuration, repacking the war,
> redeploying).
>
> For the next version of our app, I would like to move the log4j
> configuration to a place outside of the war.
> For Tomcat I would like to use $catalina.home/conf/ilink/GW-log4j2.xml
> and for Wildlfy I would like to use
> $jboss.home.dir/conf/ilink/GW-log4j2.xml
> (with $catalina.home and $jboss.home.dir being system properties that are
> defined in the two servers)
>
> Since the configuration file path is only known at runtime I cannot use
> the servlet initialization parameter ‘log4jConfiguration’ in web.xml.
> So I looked at log4j's automatic configuration [1].
> This led me to the idea to use a ServletContextListener to determine if
> the app is running in WIldFly or in Tomcat and then setting the system
> property $log4j.configurationFile accordingly.
>
> But as you point out, the ServletContextListener is executed too late.
> That explains why it does not work in my case 2 (when the Tomcat service
> is restarted).
> I still don’t understand why it does work in my case 1 (when the app is
> being redeployed in a running Tomcat), but that is not so important as this
> does not seem to be the correct approach anyway.
>
> Also, thanks for pointing out what should have been obvious: that other
> web apps on the same server will be affected when I set the
> `log4j2.configurationFile` property.
> Not a good idea.
>
> Am I trying something unusual here when I attempt to make the app decide
> where the log4j configuration file is located?
> Is there any other way in which I can achieve this?
> Is there an API for this?
>
> Thanks,
> Piers
>
> [1]
> https://logging.apache.org/log4j/2.x/manual/configuration.html#automatic-configuration
>
>
>
> > Am 15.03.2024 um 07:45 schrieb Piotr P. Karwasz <piotr.karw...@gmail.com
> >:
> >
> > Hi Piers,
> >
> > On Thu, 14 Mar 2024 at 14:08, Piers Uso Walter <piers.wal...@ilink.de>
> wrote:
> >> However, what I was trying to achieve by using a servlet context
> listener was to be able to set the location of the log4j configuration file
> at run time.
> >> I’m trying to make the app compatible with different app servers where
> configuration files are typically placed in different locations.
> >> So I’m figuring out at run time which app server the app is running in,
> and based on that I know where to expect the log4j configuration file.
> >
> > Can provide more details as to where the path to the configuration
> > file is actually stored? If you change the `log4j2.configurationFile`
> > property, other web apps on the same server will be affected, which
> > might be an unpleasant surprise to users. There are less invasive ways
> > to do that.
> >
> > I also wonder if maintaining container specific code is worth the
> > effort. Many application servers have a detailed guide to configuring
> > logging (e.g. WildFly[1]). Users might be unwilling to learn yet
> > another way to configure logging.
> >
> > Sure, Tomcat is an exception, that is why I maintain a small set of
> > Log4j Core plugins and Tomcat extensions[2] to help users
> > administering logging at a global level.
> >
> > Piotr
> >
> > [1] https://docs.wildfly.org/31/Admin_Guide.html#Logging
> > [2] https://github.com/copernik-eu/log4j-tomcat
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
> > For additional commands, e-mail: log4j-user-h...@logging.apache.org
> >
>
>

-- 
"Hell hath no limits, nor is circumscrib'd In one self-place; but where we
are is hell, And where hell is, there must we ever be" --Christopher
Marlowe, *Doctor Faustus* (v. 111-13)

Reply via email to