如何记录Akka Stream的流量?

时间:2017-02-01 12:54:18

标签: scala akka akka-stream

我有一个带有单个流/图的Akka Stream应用程序。我想测量源头的流量并每5秒记录一次,比如在过去的5秒钟内收到3条消息'我试过了,

someOtherFlow
  .groupedWithin(Integer.MAX_VALUE, 5 seconds)
  .runForeach(seq => 
    log.debug(s"received ${seq.length} messages in the last 5 seconds")
  )

但它仅在有消息时输出,在有0消息时没有空列表。我也想要0。这可能吗?

3 个答案:

答案 0 :(得分:5)

您可以尝试类似

的内容
  src
    .conflateWithSeed(_ ⇒ 1){ case (acc, _) ⇒ acc + 1 }
    .zip(Source.tick(5.seconds, 5.seconds, NotUsed))
    .map(_._1)

应该批量你的元素,直到tick发布它们。这受到an example in the docs的启发。

另一方面,如果您需要将其用于监控目的,您可以利用第三方工具实现此目的 - 例如Kamon

答案 1 :(得分:2)

稍微扩展Stefano的答案我创建了以下流程:

def flowRate[T](metric: T => Int = (_: T) => 1, outputDelay: FiniteDuration = 1 second): Flow[T, Double, NotUsed] =
  Flow[T]
  .conflateWithSeed(metric(_)){ case (acc, x) ⇒ acc + metric(x) }
  .zip(Source.tick(outputDelay, outputDelay, NotUsed))
  .map(_._1.toDouble / outputDelay.toUnit(SECONDS))

def printFlowRate[T](name: String, metric: T => Int = (_: T) => 1,
                     outputDelay: FiniteDuration = 1 second): Flow[T, T, NotUsed] =
  Flow[T]
    .alsoTo(flowRate[T](metric, outputDelay)
              .to(Sink.foreach(r => log.info(s"Rate($name): $r"))))

第一个将流量转换为每秒的速率。您可以提供metric,它为每个通过的对象提供值。假设您想测量字符串流中的字符比率,那么您可以传递_.length。第二个参数是流速报告之间的延迟(默认为一秒)。

第二个流可用于内联打印流速以进行调试,而无需修改通过流的值。例如

stringFlow
  .via(printFlowRate[String]("Char rate", _.length, 10 seconds))
  .map(_.toLowercase) // still a string
  ...

将每隔10秒显示字符的平均速率(每秒)。

答案 2 :(得分:2)

一个示例akka流日志记录。

  implicit val system: ActorSystem = ActorSystem("StreamLoggingActorSystem")
  implicit val materializer: ActorMaterializer = ActorMaterializer()
  implicit val adapter: LoggingAdapter = Logging(system, "customLogger")
  implicit val ec: ExecutionContextExecutor = system.dispatcher

  def randomInt = Random.nextInt()

  val source = Source.repeat(NotUsed).map(_ ⇒ randomInt)


  val logger = source
    .groupedWithin(Integer.MAX_VALUE, 5.seconds)
    .log(s"in the last 5 seconds number of messages received : ", _.size)
    .withAttributes(
      Attributes.logLevels(
        onElement = Logging.WarningLevel,
        onFinish = Logging.InfoLevel,
        onFailure = Logging.DebugLevel
      )
    )

  val sink = Sink.ignore

  val result: Future[Done] = logger.runWith(sink)

  result.onComplete{
    case Success(_) =>
      println("end of stream")
    case Failure(_) =>
      println("stream ended with failure")
  }

源代码为here