【问题标题】:Actor MDC context in aroundReceive methodaroundReceive 方法中的 Actor MDC 上下文
【发布时间】:2016-05-31 22:54:11
【问题描述】:

我有一个 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 中设置MDC 上下文。要使这项工作SomeActor#receice() 需要在与BaseActor#aroundReceive() 方法相同的线程中执行。

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

【问题讨论】:

    标签: java akka mdc


    【解决方案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 实现)中找到。

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

    【讨论】:

    • DiagnosticLoggingAdapter 不成功的原因在this answer 中有解释。至于覆盖aroundReceive,这被标记为内部API,并且仅当您将类放入包akka.actor 时才有效,这是一个hack。见this answer。不过不确定在 Java 中可以做什么。
    猜你喜欢
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2015-07-17
    • 2019-07-08
    • 2018-08-13
    • 1970-01-01
    相关资源
    最近更新 更多