0

我有一个 Java Akka 应用程序,我想根据消息中的信息为每个消息处理设置一个单独的 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);
        }
    }
}

以及实际的actor实现:

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

我想确保里面的所有日志条目SomeActor#receive()都将在BaseActor. 为了使这项工作SomeActor#receice() 需要在与BaseActor#aroundReceive()方法相同的线程中执行。

我没有找到有关行为的任何信息aroundReceive- 是否总是在与实际receive方法相同的线程中执行?根据我的测试,它总是在同一个线程中执行。

4

1 回答 1

2

我能够自己找出正确的实现,并希望分享它以防有人遇到同样的问题。

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 上下文进行记录。可以在这篇有趣的博客文章(使用 Scala 实现)中找到更多信息。

DiagnosticLoggingAdapter注意:尽管 Akka 有设置 MDC 上下文的方法,但 我无法使用 Akka 实现相同的功能。

于 2016-06-04T01:52:46.343 回答