Logging all messages sent to an Akka TestKit TestProbe
Asked Answered
T

3

8

I'm trying to log all messages received by a TestKit TestProbe, which is proving to be somewhat difficult. I'm aware of the Actor Logging section in the docs where it says one should use the debug.receive option in combination with a LogginReceive block. This however doesn't work when I'm not in control of the actor's implementation.

The only idea I had was subclassing akka.testkit.TestActor to use a LoggingReceive and then subclass TestKit to make it create instances of my TestActor subclass instead, but that didn't work because most functionality there is private to the akka namespace (and for good reason, I suppose).

Treadle answered 16/11, 2012 at 16:43 Comment(0)
B
4

Sorry, got your question a little wrong at first, so here is my approach.

Create a wrapper actor, that logs the messages:

class LoggingActor(fac: => Actor) extends Actor {

  val underlying = context.system.actorOf(Props(fac))

  def receive = {
    LoggingReceive {
      case x ⇒ underlying.tell(x, sender)
    }
  }
}

and then just create your TestActorRef with your actor wrapped in the LoggingActor:

  val echo = TestActorRef(new LoggingActor(new FooActor))

  echo ! "hello world"
Bays answered 16/11, 2012 at 18:28 Comment(0)
B
15

There is a (probably surprisingly) simple answer:

probe.setAutoPilot(new TestActor.AutoPilot {
  def run(sender: ActorRef, msg: Any) = {
    log.debug("whatever")
    this
  }
})
Bolan answered 21/11, 2012 at 15:20 Comment(2)
maybe simpler, but somehow cryptic. What's an AutoPilot? The doc is silent on that.Shantelleshantha
AutoPilot is in docs now, fyi. Not the simplest concept but the above code is pretty straightforward and does the trick (I just log sender & msg values instead of "whatever" literal, obviously).Ballesteros
M
5

Using Ronald's answer I wrote this to have a simpler way to define my probes:

object LoggingTestProbe {
  def apply()(implicit system: ActorSystem) : TestProbe = {
    val probe = TestProbe()
    probe.setAutoPilot(new TestActor.AutoPilot {
      def run(sender: ActorRef, msg: Any) = {
        val other = sender.path
        val me = probe.ref.path
        system.log.debug(s"$me received $msg from $other")
        this
      }
    })
    probe
  }
}

Having this I define my probes using LoggingTestProbe() instead of TestProbe().

I'm new to Scala so this might not be optimal but works great for me.

Mutton answered 27/12, 2013 at 19:4 Comment(0)
B
4

Sorry, got your question a little wrong at first, so here is my approach.

Create a wrapper actor, that logs the messages:

class LoggingActor(fac: => Actor) extends Actor {

  val underlying = context.system.actorOf(Props(fac))

  def receive = {
    LoggingReceive {
      case x ⇒ underlying.tell(x, sender)
    }
  }
}

and then just create your TestActorRef with your actor wrapped in the LoggingActor:

  val echo = TestActorRef(new LoggingActor(new FooActor))

  echo ! "hello world"
Bays answered 16/11, 2012 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.