如何在运行时更改 log4j2.xml 中的记录器级别而不重新启动 tomcat 服务

How to change logger level in log4j2.xml at runtime without restarting tomcat service

我之前使用的是 log4j 1.2,最近迁移到 log4j 2.0 我在 web.xml

的 log4j 1.2 中使用下面的监听器 class
<listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener> 

这个侦听器 class 在 log4j 2.0 之后被删除了,我想替换这个侦听器 class 这允许我在运行时更改记录器级别并更新而无需重新启动我的 tomcat 服务网络应用程序。

我试过下面的侦听器,但这也在 tomcat 中更改 log4j2.xml

中的配置时重新启动
 <listener>
        <listener-class>org.apache.logging.log4j.core.web.Log4jContextListener</listener-class>
 </listener>

我在更改 log4j2.xml 时看到以下异常和警告,然后它重新启动 tomcat:

WARNING: The web application [demo] appears to have started a thread named [pool-UCCAdminMonitor-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 java.lang.Thread.run(Unknown Source)
Jul 14, 2020 8:36:25 AM org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads

Exception in thread "Log4j2-TF-10-ConfiguratonFileWatcher-19" java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [META-INF/services/javax.xml.parsers.DocumentBuilderFactory]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1385)
    at org.apache.catalina.loader.WebappClassLoaderBase.findResources(WebappClassLoaderBase.java:985)
    at org.apache.catalina.loader.WebappClassLoaderBase.getResources(WebappClassLoaderBase.java:1086)
    at java.util.ServiceLoader$LazyIterator.hasNextService(Unknown Source)
    at java.util.ServiceLoader$LazyIterator.hasNext(Unknown Source)
    at java.util.ServiceLoader.hasNext(Unknown Source)
    at javax.xml.parsers.FactoryFinder.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.xml.parsers.FactoryFinder.findServiceProvider(Unknown Source)
    at javax.xml.parsers.FactoryFinder.find(Unknown Source)
    at javax.xml.parsers.DocumentBuilderFactory.newInstance(Unknown Source)
    at org.apache.logging.log4j.core.config.xml.XmlConfiguration.newDocumentBuilder(XmlConfiguration.java:183)
    at org.apache.logging.log4j.core.config.xml.XmlConfiguration.<init>(XmlConfiguration.java:89)
    at org.apache.logging.log4j.core.config.xml.XmlConfiguration.reconfigure(XmlConfiguration.java:272)
    at org.apache.logging.log4j.core.LoggerContext.onChange(LoggerContext.java:752)
    at org.apache.logging.log4j.core.util.AbstractWatcher$ReconfigurationRunnable.run(AbstractWatcher.java:92)
    at java.lang.Thread.run(Unknown Source)

INFO: Illegal access: this web application instance has been stopped already. Could not load [org.apache.logging.log4j.core.lookup.JndiLookup]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.logging.log4j.core.lookup.JndiLookup]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1385)
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1373)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1226)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188)
    at org.apache.logging.log4j.util.LoaderUtil.loadClass(LoaderUtil.java:167)
    at org.apache.logging.log4j.util.LoaderUtil.newInstanceOf(LoaderUtil.java:209)
    at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:230)
    at org.apache.logging.log4j.core.util.Loader.newCheckedInstanceOf(Loader.java:311)
    at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:112)
    at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:129)
    at org.apache.logging.log4j.core.config.xml.XmlConfiguration.<init>(XmlConfiguration.java:76)
    at org.apache.logging.log4j.core.config.xml.XmlConfiguration.reconfigure(XmlConfiguration.java:272)
    at org.apache.logging.log4j.core.LoggerContext.onChange(LoggerContext.java:752)
    at org.apache.logging.log4j.core.util.AbstractWatcher$ReconfigurationRunnable.run(AbstractWatcher.java:92)

Log4j 2 不要求您提供自己的侦听器。相反,只需在您的配置元素中添加 monitorInterval=nn log4j2.xml,其中 nn 是检查配置的秒数。然后,Log4j 将以该时间间隔轮询文件并在配置发生更改时重新加载配置。

回答我自己的问题 - 首先需要在 web.xml 中添加以下过滤器和监听器:

    <listener>
        <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
    </listener>
 
    <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><!-- Servlet 3.0 w/ disabled auto-initialization only; not supported in 2.5 -->
    </filter-mapping>

log4j2.xml 的路径应该是 /WEB-INF/log4j2。xml 此后,当我们更改记录器级别时,它不会重新启动 tomcat 服务。