Thad,

Thanks so much. This looks exactly what I want to do.
But somehow I never got your code to work.


I finally modified your approach a bit, and now it works for me.
I am now able to dynamically set the location of the log4j configuration file 
in my app.
And this works not just when the app is deployed/redeployed, but also when the 
Tomcat service is restarted after the app has been deployed.


I made these changes to your code:

1.
LogListener is now a subclass of Log4jServletContextListener, instead of just 
implementing ServletContextListener.
So I’m only declaring a single listener in web.xml.

2.
I’m not using the servlet init parameter Log4jWebSupport.LOG4J_CONFIG_LOCATION 
to set the config file location.
Instead, I’m initializing a log4j Configurator from the file.

-----------------------------------------------------

LogListener.java:
public class LogListener extends Log4jServletContextListener {
        @Override
         public void contextDestroyed(ServletContextEvent event) {
                 super.contextDestroyed(event);
        }

        @Override
        public void contextInitialized(ServletContextEvent event)
        {
                logConfigPath = … // Determine the path of the log 
configuration file

                Configurator.initialize(null, logConfigPath);
                super.contextInitialized(event);
        }
}


web.xml:
<listener>
         <!-- This listener *must* be first for log4j to work. -->
         
<listener-class>com.mycorp.server.rest.listeners.LogListener</listener-class>
</listener>

-----------------------------------------------------


Your email was instrumental for me being able to find this solution.
Thanks again :-)


With kind regards

Piers

-- 
Piers Uso Walter <piers.wal...@ilink.de>
ilink Kommunikationssysteme GmbH
Kurfuerstendamm 67, 10707 Berlin, Germany
+49 (30) 28526-185


> Am 21.03.2024 um 13:43 schrieb Thad Humphries <thad.humphr...@gmail.com>:
> 
> 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