2016-05-31 11 views
0

Java Akkaアプリケーションがあり、メッセージ内の情報に基づいて各メッセージ処理用に別々のMDCコンテキストを設定する必要があります。たとえば、すべてのメッセージに対して次の基本インターフェイスを使用します。aroundReceiveメソッドのMDCコンテキスト

public interface IdMessage { 
    String getId(); 
} 

また、私はすべての俳優たちのために、以下の基本の俳優を持っている:

public class BaseActor extends AbstractActor { 

    private final DiagnosticLoggingAdapter log = Logging.apply(this); 

    @Override 
    public void aroundReceive(PartialFunction<Object, BoxedUnit> receive, Object msg) { 
     if (msg instanceof IdMessage) { 
      final Map<String, Object> originalMDC = log.getMDC(); 
      log.setMDC(ImmutableMap.of("id", ((IdMessage) msg).getId())); 
      try { 
       super.aroundReceive(receive, msg); 
      } finally { 
       if (originalMDC != null) { 
        log.setMDC(originalMDC); 
       } else { 
        log.clearMDC(); 
       } 
      } 
     } else { 
      super.aroundReceive(receive, msg); 
     } 
    } 
} 

そして、実際の俳優の実装:

public class SomeActor extends BaseActor { 
    SomeActor() { 
    receive(ReceiveBuilder 
        .match(SomeMessage.class, message -> { 
         ... 
        } 
    } 
} 

SomeActor#receive()内のすべてのログエントリに、BaseActorにMDCコンテキストが設定されていることを確認したいと思います。この作業をSomeActor#receice()にするには、BaseActor#aroundReceive()メソッドと同じスレッドで実行する必要があります。

aroundReceiveの動作に関する情報が見つかりませんでした - これは実際にreceiveメソッドと同じスレッドで実行される予定ですか?私のテストに基づいて、常に同じスレッドで実行されます。

答えて

1

私は自分自身で適切な実装を見つけ出すことができ、誰かが同じ問題に直面した場合にそれを共有したいと思います。

aroundReceivereceiveと同じスレッドで実行されるため、これはMDCコンテキストを設定するのに適しています。

私はここで、MDCのコンテキストを設定するためのorg.slf4j.MDCを使用し、完全なコードは次のとおりです。

import java.util.Map; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.slf4j.MDC; 

import com.google.common.collect.ImmutableMap; 

import akka.actor.AbstractActor; 
import scala.PartialFunction; 
import scala.runtime.BoxedUnit; 

public class BaseActor extends AbstractActor { 

    private final Logger log = LoggerFactory.getLogger(BaseActor.class); 

    @Override 
    public void aroundReceive(PartialFunction<Object, BoxedUnit> receive, Object msg) { 
     if (msg instanceof IdMessage) { 
      final Map<String, Object> originalMDC = log.getMDC(); 
      MDC.setContextMap(ImmutableMap.of("id", ((IdMessage) msg).getId())); 
      try { 
       super.aroundReceive(receive, msg); 
      } finally { 
       if (originalMDC != null) { 
        MDC.setContextMap(originalMDC); 
       } else { 
        MDC.clear(); 
       } 
      } 
     } else { 
      super.aroundReceive(receive, msg); 
     } 
    } 
} 

BaseActorの実装ではreceive内のすべてのログエントリが適切なMDCコンテキストで記録されます。追加情報はこの興味深いブログpost(Scalaの実装で)にあります。

注:MDCコンテキストを設定する方法はありますが、Akka DiagnosticLoggingAdapterと同じ機能を実現できませんでした。

+0

「DiagnosticLoggingAdapter」がトリックをしない理由は、[この回答](http://stackoverflow.com/a/31237679/843660)で説明されています。 'aroundReceive'をオーバーライドする場合、これは内部APIとしてマークされ、あなたのクラスをハックである' akka.actor'パッケージに入れる場合にのみ機能します。 [この回答](http://stackoverflow.com/a/26723452/843660)を参照してください。 Javaで何ができるかわからない – dskrvk

関連する問題