2016-05-31 37 views
0

我有一個Java阿卡應用程序,我想爲每一個消息的單獨MDC上下文處理基於該消息內的信息,例如我已經對所有消息以下基本接口:演員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

我能夠自己找出正確的實施方法,並希望在遇到同樣問題時分享。

aroundReceive將在與receive相同的線程中執行,因此這是設置MDC上下文的正確位置。

我用org.slf4j.MDC用於設置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