2014-09-27 2 views
2

У меня был Google для этого, посмотрел на несколько предложений и ничего не помогло.SLF4J MDC Memory Leak

У меня есть приложение JAX-RS, которое с использованием MDC, когда попадает конечная точка, устанавливает транзакцию для упрощения отладки. Однако, когда я останавливаю или перезапускаю Tomcat, журналы заполняются такими статьями:

27-Sep-2014 09: 42: 14.858 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoader.checkThreadLocalMapForLeaks Веб-приложение [/core-1.0.0-RC2] создало ThreadLocal с ключом типа [org.apache.log4j.helpers.ThreadLocalMap] (значение [[email protected]]) и значение типа [java.util.Hashtable] (значение [{siteCode = 000tst, transactionId = dc8f3a1b-1d7a-4f91-abf6-58d015632d03}]), но не удалось удалить его, когда веб-приложение было остановлено. С течением времени темы будут обновляться, чтобы избежать возможной утечки памяти.

У меня есть RequestFilter где MDC называется:

import org.slf4j.MDC; 

import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import java.io.IOException; 
import java.util.UUID; 

public void filter(ContainerRequestContext containerRequestContext) throws IOException { 

    String siteCodeHeader = containerRequestContext.getHeaderString("Site-Code"); 

    if (siteCodeHeader != null) { 
     MDC.put("siteCode", siteCodeHeader); 
    } else { 
     MDC.put("siteCode", "NULL"); 
    } 
    MDC.put("transactionId", UUID.randomUUID().toString()); 


} 

Это мои sl4fj зависимости:

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

Если у меня есть ResponseFilter с MDC.clear() Он удаляет значения из MDC, но, похоже, не очищает резьбу:

27-сент.-2014 09: 12: 58.216 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoader.checkThreadLocalMapForLeaks Мы b application [/core-1.0.0-RC2] создал ThreadLocal с ключом типа [org.apache.log4j.helpers.ThreadLocalMap] (значение [[email protected]]) и значение type [java.util.Hashtable] (значение [{}]), но не удалось удалить его, когда веб-приложение было остановлено. С течением времени темы будут обновляться, чтобы избежать возможной утечки памяти.

По-видимому, он был исправлен в log4j 1.2.17, но изменения, похоже, не отфильтровались до slf4j.

ответ

1

Используя сочетание двух предыдущих ответов, я смог исправить эту проблему.

Я использовал реализацию log4j для MDC, а не SLF4J, и добавил ResponseFilter, чтобы выполнить очистку. Он может повлиять на него или не повлиял, но я также использовал аннотации поставщиков, а не задавал классы в web.xml.

RequestFilter (так же):

package com.example.jaxrs; 

import org.apache.log4j.MDC; 

import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.ext.Provider; 
import java.io.IOException; 
import java.util.UUID; 

@Provider 
public class TransactionIdentifierRequestFilter implements ContainerRequestFilter { 

    @Override 
    public void filter(ContainerRequestContext containerRequestContext) throws IOException { 

     String siteCodeHeader = containerRequestContext.getHeaderString("Site-Code"); 

     if (siteCodeHeader != null) { 
      MDC.put("siteCode", siteCodeHeader); 
     } else { 
      MDC.put("siteCode", "NULL"); 
     } 
     MDC.put("transactionId", UUID.randomUUID().toString()); 

    } 
} 

ResponseFilter:

package com.example.jaxrs; 

import org.apache.log4j.MDC; 

import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerResponseContext; 
import javax.ws.rs.container.ContainerResponseFilter; 
import javax.ws.rs.ext.Provider; 
import java.io.IOException; 

@Provider 
public class TransactionIdentifierResponseFilter implements ContainerResponseFilter { 

    @Override 
    public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException { 
     MDC.clear(); 
    } 
} 

web.xml

<init-param> 
    <param-name>jersey.config.server.provider.packages</param-name> 
    <param-value>com.example.jaxrs</param-value> 
</init-param> 
+0

Это неправильный путь. Теперь вы привязали свой код к Log4J. Вы должны были очистить MDC в первую очередь [SLF4J означает] (http://www.slf4j.org/api/org/slf4j/MDC.html#clear%28%29). –

+0

Это не сработало. SLF4J MDC построен на старой версии log4j до того, как было установлено исправление 1.2.17. Обнаружили это, посмотрев на фактические источники. Основная структура ведения журнала, которую я использовал для slf4j, была log4j, поэтому не требовалось никаких новых зависимостей и т. Д., Или полный каротаж. –

+0

Вот почему я посоветовал обновить log4j явно. –

0

Это явно не проблема SLF4J, а проблема Log4J. Добавьте фиксированную версию Log4J как прямую зависимость от вашего POM с областью runtime, и ваша проблема должна исчезнуть.

+0

Не работает. Я использую версию MDF SLF4j, а не Log4J, и последняя версия log4j является зависимостью для другой зависимости, поэтому она уже присутствовала. –

+0

, то вы пропустили очистку MDC после того, как запрос был обработан. –

+0

Я очистил MDC после и вернул, что, хотя значения были очищены, threadlocal все еще остается. –

1

MDC удерживаются в текущей резьбе, используя ThreadLocal. Если вы добавляете значения в фильтр, вы должны удалить их после вызова службы.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
    try 
    { 

    //add your mdcs 

    // proceed along the chain 
    chain.doFilter(request, response); 

    } 
    finally 
    { 

    //remove your mdcs 

    } 
} 
+0

Я создал класс, который расширяет ServletContainer, перезаписывает метод doFilter() и устанавливает весовой класс сервлета в мой пользовательский класс , однако doFilter, похоже, не попадает. Нужно ли мне явно называть doFilter каким-то образом? –

+0

Перед описанием сервлета 3.0 можно добавить конфигурацию фильтра в файл web.xml. Взгляните на http://stackoverflow.com/questions/11092421/spring-dispatcherservlet-code-to-execute-before-it – Hannes