Question

The stack I am using at the moment is:

  • log4j2 rc1
  • spring 3.2 core and web
  • tomcat 7.0.47
  • java 1.6.0_45
  • Windows 7

I don't have the ability to alter the tomcat version or java version and I would prefer not to alter the log4j version and spring version.

Essentially, when I undeploy my webapp I receieve a SEVERE warning saying:

SEVERE: The web application [/MyApp] appears to have started a thread named
[AsyncAppender-AsyncFile] but has failed to stop it. This is very likely to 
create a memory leak

I can confirm that it does create a memory leak and this is what I am trying to fix.

So far I have attempted to create a custom ServletContextListener which contains the following code:

@Override
public void contextDestroyed(ServletContextEvent event) {
    System.out.println("Shutting down logger");
    try {
        ((Log4jWebSupport) event.getServletContext().getAttribute(
            Log4jWebSupport.SUPPORT_ATTRIBUTE)).clearLoggerContext();
        ((LifeCycle) LogManager.getContext()).stop();
    } catch (Exception e) {

    }
}

None of these two lines seems to fix the problem, however I can confirm that this code is being executed due to my sysout statement appearing in the tomcat console.

I am using log4j2 through an interceptor which I am setting up using Spring

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <ref bean="LoggingInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
<bean id="LoggingInterceptor" class="MyLoggerClass">

The interceptor works correctly and the logs appear where I expect them to. My implementation of the logger is:

private static Logger log = LogManager.getLogger("MetricLogger");

public void log(LogPayload payload) {
    if(payload != null){
        log.info(payload.get());
    }
}

Where LogPayload.get() returns a String.

As I am using the logging facility across multiple webapps I have created a separate jar file containing this and the classes recording the measurements. I have included this using maven and I compile it into the final war file I deploy to tomcat. This war file is included on a per app basis and is not included in the global tomcat/lib folder.

Does anyone have any insight as to why I get my memory leak issue and what the possible solutions are to fixing this?

Many thanks for your help and please let me know if you need further information.

Was it helpful?

Solution

The solution to this that I have so far found is that I need to include the following snippet in the web.xml.

<listener>
    <listener-class>org.apache.logging.log4j.core.web.Log4jServletContextListener</listener-class>
</listener>

<filter>
    <filter-name>log4jServletFilter</filter-name>
    <filter-class>org.apache.logging.log4j.core.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>
</filter-mapping>

This is specific to servlet spec 2.5. This seems to resolve the memory leak issue.

OTHER TIPS

In case you are facing this issue recently you should note the following:

If you are using servlet 3.0+ and tomcat > 7.0.43 or Tomcat 8 there are no configuration needed, you just have to provide the correct maven dependencies to make log4j2 aware of running in a webcontainer like the following (in addition we use slf4j):

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.11.0</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.11.0</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.11.0</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.11.0</version>
</dependency>

Since in our case the log4j-web artifact was missing we faced the same warning which said "... started a thread named [AsyncAppender-AsyncFile] but has failed to stop it ..."

After providing the mentioned dependencies the warning is gone.

you can read more about requirements here

Adding the below snippet worked for me to get rid of memory leak due to Async-Appender threads not getting shut down even after the application shutdown. Thank you @kipper_t.

<listener>
    <listener-class>org.apache.logging.log4j.core.web.Log4jServletContextListener</listener-class>
</listener>

<filter>
    <filter-name>log4jServletFilter</filter-name>
    <filter-class>org.apache.logging.log4j.core.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>log4jServletFilter</filter-name>
    <url-pattern>/*</url-pattern>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top