How do I register the internal state of an actor when receiving?

For actors that can be expressed succinctly enough, the frustration needs to be added to blocks ( {...}

) so that I can add a log command. I would like to register my internal state before the message is processed and then after the message is processed - is this possible?

def receive = {
    // I want to log here instead and remove the non-critical logs from below
    //  e.g. log.debug(s"Received $message")
    //       log.debug(s"Internal state is $subscriptions")
    case RegisterChannel(name, owner) => {
      getChannel(name) match {
        case Some(deadChannel: DeadChannel) => {
          subscriptions += (RealChannel(name, Server(owner)) -> subscriptions(deadChannel))
          subscriptions -= deadChannel
          context.watch(owner)
          log.debug(s"Replaced $deadChannel with a real channel $channels")
        }
        case Some(realChannel: RealChannel) =>
          log.error(s"Refusing to use RegisterChannel($name, $owner) due to $realChannel")
        case None => {
          subscriptions += (RealChannel(name, Server(owner)) -> Vector())
          context.watch(owner)
          log.debug(s"Registered a new channel $channels")
        }
      }
    }

    case Terminated(dead) => {
      getRole(dead) match {
        case Some(client: Client) => // Remove subscriptions
          log.debug(s"Received Client Terminated($dead) $client")
          subscriptionsFor(client).foreach { subscription =>
            subscriptions += (subscription._1 -> subscription._2.filterNot(c => c == client))
          }
        case Some(server: Server) => { // Remove any channels
          log.debug(s"Received Server Terminated($dead) $server")
          channelsBy(server).foreach { realChannel =>
            subscriptions += (DeadChannel(realChannel.name) -> subscriptions(realChannel))
            subscriptions -= realChannel
          }
        }
        case None =>
          log.debug(s"Received Terminated($dead) but no channel is registered")
      }
    }
    // I want to log here as well, to see what effect the message had
    //  e.g. log.debug(s"Finished $message")
    //       log.debug(s"Internal state is now $subscriptions")
}

      

I'm not sure if this is a special Akka or Scala related question, so I marked the tags

EDIT: After trying @aepurniet's answer, I have no idea how to solve the compiler error. receive needs to be returned PartialFunction[Any,Unit]

, but if the match is not the only element in => {...}

it seems to be returnedAny=>AnyRef

// Compiler error because msg=>{...} is not proper type
def receive = msg => { 
    log.info(s"some log")

    msg match {
      case RegisterChannel(name, owner) => {
        getChannel(name) match {
    <snip>

      

+3


source to share


3 answers


received = { case ... }

actually shortened for received = msg => msg match { case ... }

. you can rewrite receive = msg => { log.info(..); msg match { case ... } }

, you may need to specify the types additionally.



+5


source


There is akka.event.LoggingReceive which you can use like this:

def receive = LoggingReceive {
  case ...
}

      

Then you set akka.actor.debug.receive

to on

, and this will write (in DEBUG) all messages received and handle them or not.



See the "Actor Tracking" section in the official Akka documentation.

For additional status logging, you can do something similar to LoggingReceive

def withStateLogging(handler: Receive): Receive = {
  case msg if handler.isDefinedAt(msg) ⇒
    log.debug("before actual receive")
    log.debug(s"received: $msg")
    log.debug(s"state: $state")
    handler(msg)
    log.debug("after actual receive")
    log.debug(s"finished: $msg")
    log.debug(s"state: $state")
}

def receive = withStateLogging {
  case ...
}

      

+3


source


The compiler complains because the return type of the Actor # receive is Receive, which is actually defined as

type Receive = PartialFunction[Any, Unit]

      

Here is a good example of how your problem can be solved with stackable traits: how to add a registration function when sending and receiving actions in akka

It's a little tricky and overrides the default PartialFunction behavior .

+1


source







All Articles