有没有可能在andThens链中“插入到任何地方”的finagle中有一个通用的日志记录过滤器?

PhD*_*PhD 5 scala function-composition finagle

在我们的代码中,我们创建了许多“ finagle管道”,如下所示:

val f1 = new Filter[A,B,C,D](...)
val f2 = new SimpleFilter[C,D](...)
val f3 = new Filter[C,D,E,F](...)
val s = new Service[E,F](...)

val pipeline: Service[A,B] = f1 andThen f2 andThen f3 andThen s
Run Code Online (Sandbox Code Playgroud)

我现在希望能够在这样的链中的任何地方 “插入”记录器。记录器只会记录请求进入并收到响应的事实。像这样:

class LoggerFilter[Req, Resp](customLog: String) extends SimpleFilter[Req, Resp] with LazyLogging{
  override def apply(request: Req, service: Service[Req, Resp]): Future[Resp] = {
    logger.info(s"$customLog => Request: ${request.getClass.getName} -> ${service.toString}")
    service(request).map{resp =>
      logger.info(s"$customLog => Response: ${resp.getClass.getName} -> ${request.getClass.getName}")
      resp
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,我们必须不断声明多个记录器,以便类型可以正确对齐,然后在“正确的位置”插入。

val logger1 = new LoggerFilter[A,B]("A->B Logger")
val logger2 = new LoggerFilter[C,D]("C->D Logger")
val logger3 = new LoggerFilter[E,F]("E->F Logger")

val pipeline = logger1 andThen f1 andThen f2 andThen logger2 andThen f3 andThen logger3 andThen s
Run Code Online (Sandbox Code Playgroud)

有没有办法可以避免这种情况?是否只有一个记录器可以自动推断Req/Resp类型并在链中“可插入任何地方”?

例如:

val logger = getTypeAgnosticLogger // What's the implementation?

val pipeline = logger andThen f1 andThen f2 andThen logger andThen f3 andThen logger andThen s

// Is this possible - params for logger to print?
val pipeline = logger("f1") andThen f1 andThen f2 andThen logger("f3") andThen f3 andThen logger("s") andThen s
Run Code Online (Sandbox Code Playgroud)

Ast*_*rid 5

我想不出一种定义自动记录器的方法。我的第一个想法是按照@Krzysztof的建议依赖于编译器类型推断,但是由于带有参数的记录器而最终导致类型错误,[Nothing, Nothing]因此似乎那里的编译器推断触发得太早了。鉴于此,我不确定在没有每种记录器显式类型的情况下,您的描述方式是否可行。

但是,要获得非常相似的功能,您可以使用在运行之前附加Logger 的方法来扩展Filterand ServicewithLogging。到那时,您已经具有足够的类型信息来显式构造记录器,并且它还使您可以传递参数:

implicit class FilterLogging[ReqIn, RepOut, ReqOut, RepIn](filter: Filter[ReqIn, RepOut, ReqOut, RepIn]) {

  def withLogging(param: String) : Filter[ReqIn, RepOut, ReqOut, RepIn] = new LoggerFilter[ReqIn, RepOut](param).andThen(filter)
}

implicit class ServiceLogging[Req, Rep](service: Service[Req, Rep]) {

  def withLogging(param: String) : Service[Req, Rep] = new LoggerFilter[Req, Rep](param).andThen(service)
}

val pipeline = f1.withLogging("f1") andThen f2 andThen f3.withLogging("f3") andThen service.withLogging("s")
Run Code Online (Sandbox Code Playgroud)