如何解决 log4j2 滚动文件附加器触发时抛出的异常?
How to resolve exception(s) thrown when log4j2 rolling file appender triggers?
日志似乎可以正常滚动和归档,但是在指定的触发时间或附近我注意到 tomcat catalina.out 中的异常(有时一次,其他时候以每秒 1 次的速度淹没日志).任何帮助表示赞赏。
执行环境:
- Tomcat 版本:Apache Tomcat/8.5.3
- JVM 版本:1.8.0_92-b14
- JVM 供应商:甲骨文公司
- OS 姓名:Linux
- OS 版本:2.6.32-642.3.1.el6.x86_64
- OS 架构:amd64
组装 WAR 似乎在 WEB-INF/lib 中有合适的 jar,包括:
- log4j-api-2.6.2.jar
- log4j-core-2.6.2.jar
- log4j-slf4j-impl-2.6.2.jar
- log4j-web-2.6.2.jar
异常:
2016-10-27 16:11:24,002 Log4j2-Log4j2Scheduled-2 ERROR Error running command java.lang.NoClassDefFoundError: org/apache/logging/log4j/core/impl/Log4jLogEvent$Builder
at org.apache.logging.log4j.core.appender.rolling.PatternProcessor.formatFileName(PatternProcessor.java:234)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purgeAscending(DefaultRolloverStrategy.java:323)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purge(DefaultRolloverStrategy.java:306)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.rollover(DefaultRolloverStrategy.java:524)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:220)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:155)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy.rollover(CronTriggeringPolicy.java:127)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy.access0(CronTriggeringPolicy.java:40)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy$CronTrigger.run(CronTriggeringPolicy.java:144)
at org.apache.logging.log4j.core.config.ConfigurationScheduler$CronRunnable.run(ConfigurationScheduler.java:180)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
异常 2:
The web application [my-services] appears to have started a thread named [Log4j2-Log4j2Scheduled-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(LockSupport.java:215)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" name="MyLog" packages="">
<Properties>
<Property name="baseDir">/var/log/tomcat</Property>
<Property name="appName">MyLog</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/${appName}.log" immediateFlush="true"
filePattern="${baseDir}/$${date:yyyy}/$${date:MM}/${appName}-$${date:yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%highlight{%d %p{INFO=INFO_,WARN=WARN_} %c{3.} (%M:%L) [%t] %m%n%ex}{FATAL=Magenta,TRACE=Normal White}" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/${appName}-*log.gz" />
<IfLastModified age="90d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%highlight{%d %p{INFO=INFO_,WARN=WARN_} %c{3.} (%M:%L) [%t] %m%n%ex}{FATAL=Magenta,TRACE=Normal White}" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="RollingFile"/>
<!--<AppenderRef ref="Console"/>-->
</Root>
</Loggers>
</Configuration>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1">
<display-name>My Services</display-name>
<!-- log4j2 configuration file -->
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>log4j2.xml</param-value>
</context-param>
<!-- my servlet -->
<servlet>
<servlet-name>my-services</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package, com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-services</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
pom.xml 依赖关系:
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- version properties -->
<jersey.version>2.23.1</jersey.version>
<jackson.version>2.7.2</jackson.version>
<spring.version>4.1.6.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.6.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- Jersey and Jackson -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- Jersey w/Tomcat 8 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
</dependencies>
我怀疑 Tomcat 服务器 lib 文件夹中有旧版本的 log4j 2。
如果您在网络应用程序中执行此操作,您会看到什么?那应该告诉您 Log4jLogEvent 是从哪个 jar 加载的。
System.out.println(
Log4jLogEvent.class.getResource(
"/org/apache/logging/log4j/core/impl/Log4jLogEvent.class"));
有一个 known issue with lo4j2 2.6.2 leaking threads in Tomcat webapps when they shutdown. I suspect you see ClassNotFoundExceptions because an orphaned thread is trying to load classes. This is especially likely since you're using the CronTriggeringPolicy 强制日志在午夜滚动,但在该策略执行之前重新启动您的 webapp。
已在 lo4j2 2.7 中发布修复程序。尝试提升您的版本。
日志似乎可以正常滚动和归档,但是在指定的触发时间或附近我注意到 tomcat catalina.out 中的异常(有时一次,其他时候以每秒 1 次的速度淹没日志).任何帮助表示赞赏。
执行环境:
- Tomcat 版本:Apache Tomcat/8.5.3
- JVM 版本:1.8.0_92-b14
- JVM 供应商:甲骨文公司
- OS 姓名:Linux
- OS 版本:2.6.32-642.3.1.el6.x86_64
- OS 架构:amd64
组装 WAR 似乎在 WEB-INF/lib 中有合适的 jar,包括:
- log4j-api-2.6.2.jar
- log4j-core-2.6.2.jar
- log4j-slf4j-impl-2.6.2.jar
- log4j-web-2.6.2.jar
异常:
2016-10-27 16:11:24,002 Log4j2-Log4j2Scheduled-2 ERROR Error running command java.lang.NoClassDefFoundError: org/apache/logging/log4j/core/impl/Log4jLogEvent$Builder
at org.apache.logging.log4j.core.appender.rolling.PatternProcessor.formatFileName(PatternProcessor.java:234)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purgeAscending(DefaultRolloverStrategy.java:323)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purge(DefaultRolloverStrategy.java:306)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.rollover(DefaultRolloverStrategy.java:524)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:220)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:155)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy.rollover(CronTriggeringPolicy.java:127)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy.access0(CronTriggeringPolicy.java:40)
at org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy$CronTrigger.run(CronTriggeringPolicy.java:144)
at org.apache.logging.log4j.core.config.ConfigurationScheduler$CronRunnable.run(ConfigurationScheduler.java:180)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
异常 2:
The web application [my-services] appears to have started a thread named [Log4j2-Log4j2Scheduled-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(LockSupport.java:215)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" name="MyLog" packages="">
<Properties>
<Property name="baseDir">/var/log/tomcat</Property>
<Property name="appName">MyLog</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/${appName}.log" immediateFlush="true"
filePattern="${baseDir}/$${date:yyyy}/$${date:MM}/${appName}-$${date:yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%highlight{%d %p{INFO=INFO_,WARN=WARN_} %c{3.} (%M:%L) [%t] %m%n%ex}{FATAL=Magenta,TRACE=Normal White}" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/${appName}-*log.gz" />
<IfLastModified age="90d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%highlight{%d %p{INFO=INFO_,WARN=WARN_} %c{3.} (%M:%L) [%t] %m%n%ex}{FATAL=Magenta,TRACE=Normal White}" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="RollingFile"/>
<!--<AppenderRef ref="Console"/>-->
</Root>
</Loggers>
</Configuration>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1">
<display-name>My Services</display-name>
<!-- log4j2 configuration file -->
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>log4j2.xml</param-value>
</context-param>
<!-- my servlet -->
<servlet>
<servlet-name>my-services</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package, com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-services</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
pom.xml 依赖关系:
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- version properties -->
<jersey.version>2.23.1</jersey.version>
<jackson.version>2.7.2</jackson.version>
<spring.version>4.1.6.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.6.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- Jersey and Jackson -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- Jersey w/Tomcat 8 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
</dependencies>
我怀疑 Tomcat 服务器 lib 文件夹中有旧版本的 log4j 2。
如果您在网络应用程序中执行此操作,您会看到什么?那应该告诉您 Log4jLogEvent 是从哪个 jar 加载的。
System.out.println(
Log4jLogEvent.class.getResource(
"/org/apache/logging/log4j/core/impl/Log4jLogEvent.class"));
有一个 known issue with lo4j2 2.6.2 leaking threads in Tomcat webapps when they shutdown. I suspect you see ClassNotFoundExceptions because an orphaned thread is trying to load classes. This is especially likely since you're using the CronTriggeringPolicy 强制日志在午夜滚动,但在该策略执行之前重新启动您的 webapp。
已在 lo4j2 2.7 中发布修复程序。尝试提升您的版本。