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?
The setting you mention,
akka.actor.debug.receive
is only for the Scala API for actors. This is because of the nature of how thereceive
PartialFunction
is invoked in Scala. In Scala, the actor framework first sees if there is acase
defined for the input message usingisDefinedAt
. If there is acase
defined for the message, then it will callapply
on thePartialFunction
and the message is handled. But if the message is not handled, thenapply
is not called. In order to log all messages, handled or otherwise, the Scala framework needed a facility to wrap around thePartialFunction
evaluation to log regardless, and that facility is this setting plus theLoggingReceive
utility that wraps thereceive
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, yourinstanceof
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 implementsonReceive
and logs accordingly (possibly based on that same setting) before delegating to a subclass method for actual message evaluation and handling.