2015-07-09 2 views
10

i für alle Anforderungen mdc Protokollierung im Spiel Filter in Java Ich versuche, gefolgt ich dieses Tutorial in scala und versuchte, die Umstellung auf Java http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/Mapped Diagnostic Kontext mit Spiel framewok und akka in Java-Protokollierung

aber immer noch die mdc nicht ausbreitet zu allen Ausführungskontexten. Ich verwende diesen Dispatcher als Standard-Dispatcher, aber es gibt viele Ausführungskontexte dafür. Ich brauche die mdc für alle Ausführung propagierte Kontexte

unten ist mein Java-Code

import java.util.Map; 

import org.slf4j.MDC; 

import scala.concurrent.ExecutionContext; 
import scala.concurrent.duration.Duration; 
import scala.concurrent.duration.FiniteDuration; 
import akka.dispatch.Dispatcher; 
import akka.dispatch.ExecutorServiceFactoryProvider; 
import akka.dispatch.MessageDispatcherConfigurator; 

public class MDCPropagatingDispatcher extends Dispatcher { 
    public MDCPropagatingDispatcher(
      MessageDispatcherConfigurator _configurator, String id, 
      int throughput, Duration throughputDeadlineTime, 
      ExecutorServiceFactoryProvider executorServiceFactoryProvider, 
      FiniteDuration shutdownTimeout) { 
     super(_configurator, id, throughput, throughputDeadlineTime, 
       executorServiceFactoryProvider, shutdownTimeout); 

    } 

    @Override 
    public ExecutionContext prepare() { 
     final Map<String, String> mdcContext = MDC.getCopyOfContextMap(); 
     return new ExecutionContext() { 

      @Override 
      public void execute(Runnable r) { 
       Map<String, String> oldMDCContext = MDC.getCopyOfContextMap(); 
       setContextMap(mdcContext); 
       try { 
        r.run(); 
       } finally { 
        setContextMap(oldMDCContext); 
       } 
      } 

      @Override 
      public ExecutionContext prepare() { 
       return this; 
      } 

      @Override 
      public void reportFailure(Throwable t) { 
       play.Logger.info("error occured in dispatcher"); 
      } 

     }; 
    } 

    private void setContextMap(Map<String, String> context) { 
     if (context == null) { 
      MDC.clear(); 
     } else { 
      play.Logger.info("set context "+ context.toString()); 
      MDC.setContextMap(context); 
     } 
    } 
} 



import java.util.concurrent.TimeUnit; 

import scala.concurrent.duration.Duration; 
import scala.concurrent.duration.FiniteDuration; 

import com.typesafe.config.Config; 

import akka.dispatch.DispatcherPrerequisites; 
import akka.dispatch.MessageDispatcher; 
import akka.dispatch.MessageDispatcherConfigurator; 

public class MDCPropagatingDispatcherConfigurator extends 
     MessageDispatcherConfigurator { 
    private MessageDispatcher instance; 

    public MDCPropagatingDispatcherConfigurator(Config config, 
      DispatcherPrerequisites prerequisites) { 
     super(config, prerequisites); 
     Duration throughputDeadlineTime = new FiniteDuration(-1, 
       TimeUnit.MILLISECONDS); 
     FiniteDuration shutDownDuration = new FiniteDuration(1, 
       TimeUnit.MILLISECONDS); 
     instance = new MDCPropagatingDispatcher(this, "play.akka.actor.contexts.play-filter-context", 
       100, throughputDeadlineTime, 
       configureExecutor(), shutDownDuration); 
    } 

    public MessageDispatcher dispatcher() { 
     return instance; 
    } 

} 

Filter Interceptor

public class MdcLogFilter implements EssentialFilter { 
@Override 
public EssentialAction apply(final EssentialAction next) { 
    return new MdcLogAction() { 
     @Override 
     public Iteratee<byte[], SimpleResult> apply(
       final RequestHeader requestHeader) { 
      final String uuid = Utils.generateRandomUUID(); 
      MDC.put("uuid", uuid); 
      play.Logger.info("request started"+uuid); 
      final ExecutionContext playFilterContext = Akka.system() 
        .dispatchers() 
        .lookup("play.akka.actor.contexts.play-custom-filter-context"); 
      return next.apply(requestHeader).map(
        new AbstractFunction1<SimpleResult, SimpleResult>() { 
         @Override 
         public SimpleResult apply(SimpleResult simpleResult) { 
          play.Logger.info("request ended"+uuid); 
          MDC.remove("uuid"); 
          return simpleResult; 
         } 
        }, playFilterContext); 

     } 

     @Override 
     public EssentialAction apply() { 
      return next.apply(); 
     } 
    }; 
} 

}

+0

Konnten Sie es lösen? Wenn ja, können Sie Ihre Lösung posten –

Antwort

2

Unten ist meine Lösung, im wirklichen Leben unter Beweis gestellt. Es ist in Scala und nicht für Play, sondern für Scalatra, aber das zugrundeliegende Konzept ist dasselbe. Ich hoffe, Sie können herausfinden, wie Sie dies nach Java portieren können.

Sie müssen sicherstellen, dass dieser ExecutionContext in allen asynchronen Aufrufen verwendet wird. Ich erreiche dies durch Dependency Injection, aber es gibt verschiedene Wege. Das ist, wie ich es mit subcut:

bind[ExecutionContext] idBy BindingIds.GlobalExecutionContext toSingle { 
    MDCHttpExecutionContext.fromExecutionContextWithCurrentMDC(
     ExecutionContext.fromExecutorService(
     Executors.newFixedThreadPool(globalThreadPoolSize) 
    ) 
    ) 
    } 

Die Idee hinter diesem Ansatz ist wie folgt. MDC verwendet Thread-lokalen Speicher für die Attribute und ihre Werte. Wenn eine einzelne Ihrer Anfragen auf mehreren Threads ausgeführt werden kann, müssen Sie sicherstellen, dass der neue Thread, den Sie starten, das richtige MDC verwendet. Dazu erstellen Sie einen benutzerdefinierten Executor, der das ordnungsgemäße Kopieren der MDC-Werte in den neuen Thread sicherstellt, bevor er mit der Ausführung der ihm zugewiesenen Aufgabe beginnt. Sie müssen auch sicherstellen, dass die alten Werte in den MDC übernommen werden, wenn der Thread Ihre Aufgabe beendet und mit etwas anderem fortfährt, da Threads aus einem Pool zwischen verschiedenen Anforderungen wechseln können.