i have a simple actor with 2 behavior
package com.hello
import akka.actor.{Actor, ActorLogging}
case object Ping
class Hello extends Actor with ActorLogging {
import context._
def receive: Receive = behaviorFoo
self ! Ping
def behaviorFoo: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
become(behaviorBar)
self ! Ping
}
def behaviorBar: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
}
}
this thing do those:
ping self
logging current receive function
change behavior to behaviorBar
ping self
logging current receive function
in both cases it logs "$anonfun$behaviorFoo$1"
why it is not "$anonfun$behaviorBar$1" in second log?
if i change code to
self ! Ping
def receive: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
become(behaviorFoo)
self ! Ping
}
def behaviorFoo: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
become(behaviorBar)
self ! Ping
}
def behaviorBar: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
}
it logs 3 times "$anonfun$receive$1"
is exist any way to get current behavior (Receive) function name? or i need to hardwrite like log.info("behaviorFoo") any time?
update:
for logging issues, i added
trait MyLogging extends ActorLogging {
this: Actor ⇒
private[this] val actorClassName = this.getClass.getSimpleName
private[this] var receiveName: String = {
val receiveClassName = s"${this.receive.getClass.getSimpleName}"
val left = receiveClassName.substring(0, receiveClassName.lastIndexOf("$"))
left.substring(left.lastIndexOf("$") + 1)
}
def become(behavior: Actor.Receive): Unit = {
val behaviorClassName = behavior.getClass.getSimpleName
val left = behaviorClassName.substring(0, behaviorClassName.lastIndexOf("$"))
receiveName = left.substring(left.lastIndexOf("$") + 1)
context.become(behavior)
}
def info(message: Any): Unit = log.info(s"$actorClassName : $receiveName got $message")
}
then, my actor code become
class Hello extends Actor with MyLogging {
def receive: Receive = behaviorFoo
self ! Ping
def behaviorFoo: Receive = {
case any =>
info(any)
become(behaviorBar)
self ! Ping
}
def behaviorBar: Receive = {
case any => info(any)
}
}
now logs looks like
... Hello : behaviorFoo got Ping
... Hello : behaviorBar got Ping
Maybe this is why those are called anonymous functions. The behaviorFoo
, behaviorBar
, ... names have no influence on those anonymous functions. To illustrate this point, consider this:
// this is a val!
val behaviorFoo: Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
become(behaviorBar)
self ! Ping
}
// this returns the same anonymous function
def behaviorFoo2 = behaviorFoo
With the above, you should see that the name under which you store the anonymous function has nothing to do with the anonymous function itself...
Now, if you realize what those anonymous functions are (they are partial functions, aliased with type Actor.Receive
) you could do something like below:
// not an anonymous function anymore
class BehaviourFoo extends Actor.Receive {
val anonymousFun: Actor.Receive = {
case _ =>
log.info(this.receive.getClass.getSimpleName)
become(behaviorBar)
self ! Ping
}
override def isDefinedAt(x: Any) = anonymousFun.isDefinedAt(x)
override def apply(x: Any) = anonymousFun(x)
}
// again, the name behaviorFoo doesn't matter
def behaviorFoo: Receive = new BehaviourFoo
It is certainly NOT worth the hassle, but it should help you understand what is happening.