Возможно ли иметь общий фильтр журналирования в finagle, который можно «вставить куда угодно» в цепочку andThens? - PullRequest
5 голосов
/ 10 июня 2019

В нашем коде мы создаем множество "конвейеров 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

Теперь мне бы хотелось иметь возможность "вставлять" логгеры в любое место в такую ​​цепочку.Регистратор регистрирует только тот факт, что запрос поступил и ответ получен.Примерно так:

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

При таком подходе мы должны постоянно объявлять несколько регистраторов, чтобы типы могли правильно совмещаться, а затем вставлять в «правильном месте».

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

Есть ли способ, которого можно избежать?Можно ли просто иметь один регистратор, который может автоматически выводить 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

1 Ответ

5 голосов
/ 18 июня 2019

Я не мог найти способ определения автоматического логгера. Моя первая идея заключалась в том, чтобы полагаться на вывод типа компилятора согласно предложению @ Krzysztof, но это привело к ошибке типа из-за регистратора с параметрами [Nothing, Nothing], поэтому кажется, что вывод компилятора сработал там слишком рано. Учитывая это, я не уверен, что это возможно так, как вы описываете, без явных типов для каждого регистратора.

Однако то, что вы можете сделать, чтобы получить нечто очень похожее, - это расширить классы Filter и Service с помощью метода withLogging, который присоединяет Logger перед запуском. В этот момент у вас есть достаточно информации о типе, чтобы явно создать регистратор, и он также позволяет вам ввести свой параметр:

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