如何记录接收中的内部actor状态?

时间:2014-09-26 15:44:06

标签: scala logging akka

对于可以相当简洁地表达的Actors,必须添加块({...})才能让我感到沮丧,因此我可以添加一个日志命令。我想在处理消息之前记录我的内部状态,然后在处理消息之后 - 这可能吗?

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")
}

我不确定这是否是Akka特定的或Scala模式匹配的特定问题,所以我标记了两个

编辑:在尝试了@aepurniet的回答之后,我不知道如何解决编译器错误。收到需要返回PartialFunction[Any,Unit],但当匹配不是=> {...}中的唯一项目时,它似乎正在返回Any=>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 个答案:

答案 0 :(得分:5)

received = { case ... }实际上是received = msg => msg match { case ... }的简写。您可以重写receive = msg => { log.info(..); msg match { case ... } },您可能需要另外指定类型。

答案 1 :(得分:3)

您可以使用akka.event.LoggingReceive

def receive = LoggingReceive {
  case ...
}

然后将akka.actor.debug.receive设置为on,这将记录(到DEBUG)收到的所有邮件以及是否处理过邮件。

请参阅Akka官方文档中的Tracing Actor Invocations部分。

对于其他状态记录,您可以执行与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 ...
}

答案 2 :(得分:1)

编译器抱怨因为Actor#receive返回类型是Receive,实际上定义为

type Receive = PartialFunction[Any, Unit]

以下是使用可堆叠特征解决问题的好例子:how to add logging function in sending and receiving action in akka

这有点棘手,并且会覆盖PartialFunction的默认行为。