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>
source to share
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 ...
}
source to share
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 .
source to share