【问题标题】:How to log internal actor state in receive?如何在接收中记录内部参与者状态?
【发布时间】:2014-09-26 15:44:06
【问题描述】:

对于可以相当简洁地表达的 Actor,不得不添加块 ({...}) 只是为了添加日志命令,这令人沮丧。我想在处理消息之前记录我的内部状态,然后在处理消息之后记录 - 这可能吗?

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>

【问题讨论】:

    标签: scala logging akka


    【解决方案1】:

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

    【讨论】:

    • 这看起来很接近。当我尝试它时,我遇到了您预测的类型问题,但我不知道如何解决。我已经用最后一个小问题编辑了帖子,如果您再看一看,将不胜感激
    【解决方案2】:

    您可以像这样使用akka.event.LoggingReceive

    def receive = LoggingReceive {
      case ...
    }
    

    然后您将akka.actor.debug.receive 设置为on,这将记录(到调试)收到的所有消息以及它们是否被处理。

    参见 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 ...
    }
    

    【讨论】:

      【解决方案3】:

      编译器报错是因为 Actor#receive 返回类型是 Receive 实际定义为

      type Receive = PartialFunction[Any, Unit]
      

      这是一个很好的例子,如何使用可堆叠特征解决您的问题:how to add logging function in sending and receiving action in akka

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 2021-05-23
        • 2016-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-01
        相关资源
        最近更新 更多