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 <[email protected]>
ilink Kommunikationssysteme GmbH
Kurfuerstendamm 67, 10707 Berlin, Germany
+49 (30) 28526-185
> Am 21.03.2024 um 13:43 schrieb Thad Humphries <[email protected]>:
>
> 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 <[email protected]>
> 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 <[email protected]
>>> :
>>>
>>> Hi Piers,
>>>
>>> On Thu, 14 Mar 2024 at 14:08, Piers Uso Walter <[email protected]>
>> 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: [email protected]
>>> For additional commands, e-mail: [email protected]
>>>
>>
>>
>
> --
> "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)