Logging received messages in Akka

2019-05-03 22:03发布

问题:

I am using Akka actors from within Java and am trying to turn on the logging of messages. Based on the documentation, it seems that setting akka.actor.debug.receive should cause all messages to be logged. The following test should log the "hello" message being sent and received.

import akka.actor.AbstractLoggingActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.japi.pf.ReceiveBuilder;
import akka.pattern.Patterns;
import akka.testkit.JavaTestKit;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import io.scalac.amqp.Persistent$;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import scala.concurrent.duration.Duration$;

public class LoggingTest
{
    @Before
    public void createActorSystem() {
        Config config = ConfigFactory.parseString(
                "akka: {" +
                "  actor: { debug: { receive: on, fsm: on, unhandled: on, autoreceive: on }}," +
                "  log-config-on-start: off" +
                "  ,loglevel: DEBUG" +
                "  ,stdout-loglevel: DEBUG" +
                "}");
        system = ActorSystem.create(getClass().getSimpleName(),
                                    config);

    }

    @After
    public void shutdownActorSystem() {
        JavaTestKit.shutdownActorSystem(system);
    }

    private static class TestActorWithLogging extends AbstractLoggingActor {
        public TestActorWithLogging(ActorRef target) {
            receive(ReceiveBuilder.
                    matchAny(msg -> target.tell(msg, self())).
                    build());
        }
    }

    @Test
    public void messageLogging() {
        new JavaTestKit(system) {{
            system.log().debug("Running messageLogging");

            ActorRef actor = system.actorOf(Props.create(TestActorWithLogging.class, getRef()));
            send(actor, "hello");
            expectMsgEquals("hello");
        }};
    }


    private ActorSystem system;
}

When I run the test, I get the following output. Lifecycle messages are logged, so the config is being applied. However, I don't see any log statements about the "hello" message.

Running LoggingTest
[DEBUG] [09/17/2015 16:49:48.893] [main] [EventStream] StandardOutLogger started
[DEBUG] [09/17/2015 16:49:49.020] [main] [EventStream(akka://LoggingTest)] logger log1-Logging$DefaultLogger started
[DEBUG] [09/17/2015 16:49:49.020] [main] [EventStream(akka://LoggingTest)] logger log1-Logging$DefaultLogger started
[DEBUG] [09/17/2015 16:49:49.023] [main] [EventStream(akka://LoggingTest)] Default Loggers started
[DEBUG] [09/17/2015 16:49:49.023] [main] [EventStream(akka://LoggingTest)] Default Loggers started
[DEBUG] [09/17/2015 16:49:49.050] [main] [akka.actor.ActorSystemImpl(LoggingTest)] Running messageLogging
[DEBUG] [09/17/2015 16:49:49.103] [LoggingTest-akka.actor.default-dispatcher-4] [akka://LoggingTest/system] received AutoReceiveMessage Envelope(Terminated(Actor[akka://LoggingTest/user]),Actor[akka://LoggingTest/user])
[DEBUG] [09/17/2015 16:49:49.104] [LoggingTest-akka.actor.default-dispatcher-4] [EventStream] shutting down: StandardOutLogger started
[DEBUG] [09/17/2015 16:49:49.104] [LoggingTest-akka.actor.default-dispatcher-4] [EventStream] shutting down: StandardOutLogger started
[DEBUG] [09/17/2015 16:49:49.106] [LoggingTest-akka.actor.default-dispatcher-4] [EventStream] all default loggers stopped
[DEBUG] [09/17/2015 16:49:49.111] [LoggingTest-akka.actor.default-dispatcher-3] [akka://LoggingTest/] received AutoReceiveMessage Envelope(Terminated(Actor[akka://LoggingTest/system]),Actor[akka://LoggingTest/system])
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.33 sec

What should I be doing to log the messages?

回答1:

The setting you mention, akka.actor.debug.receive is only for the Scala API for actors. This is because of the nature of how the receive PartialFunction is invoked in Scala. In Scala, the actor framework first sees if there is a case defined for the input message using isDefinedAt. If there is a case defined for the message, then it will call apply on the PartialFunction and the message is handled. But if the message is not handled, then apply is not called. In order to log all messages, handled or otherwise, the Scala framework needed a facility to wrap around the PartialFunction evaluation to log regardless, and that facility is this setting plus the LoggingReceive utility that wraps the receive PartialFunction and uses that setting to control logging.

In the Java world, you don't have this "check then apply" semantic. All messages hit the onReceive method and in there, your instanceof handling will determine if the message is handled or not. Because of this, it's pretty easy to define an abstract base Java class that implements onReceive and logs accordingly (possibly based on that same setting) before delegating to a subclass method for actual message evaluation and handling.



标签: java akka