Распространение контекста через анализатор и тело действия в игровой среде - PullRequest
0 голосов
/ 24 апреля 2018

Я распространил информацию трассировки, которая передается с запросами между службами в заголовках HTTP (специально для opentracing).

Я бы хотел, чтобы эта информация была доступна везде, чтобы я мог включать идентификатор трассировки в журналы, распространять на последующие запросы и т. Д.

Итак, я хочу проанализировать заголовки, чтобы создать Span до обработки запроса, сделать диапазон доступным для кода обработки, а затем выполнить некоторую очистку после обработки запроса.

вещей, которые я пробовал:

Сначала казалось, что Фильтр будет правильным подходом, но с этим есть несколько проблем:

  1. Установка локального хранилища потока при вызове следующего действия не очень помогает, потому что обычно большая часть работы выполняется во время или после Аккумулятора, который он возвращает. В этот момент локальное хранилище потока было сброшено.
  2. Насколько я могу судить, нет никакого способа обернуть Accumulator, чтобы этапы накопления были обернуты в контекст с локальным набором потока. Лучшее, что я смог сделать, - это использовать Accumulator.source для возвращаемого мной накопителя, а затем использовать запуск накопителя вложенных действий с источником из него и пользовательским материализатором, который упаковывает все методы для установки локальных потоков. Но это все еще не работает, я думаю, потому что материализатор отправляет в другой поток. Я настроил диспетчер по умолчанию для akka, чтобы отслеживать эти локальные потоки, но материализатор, похоже, в этом случае обходит его.
  3. Нет способа прикрепить произвольные данные к RequestHeader, теги работают только для строк. И даже если бы это было так, мне пришлось бы поменять все свои контроллеры, чтобы прочитать их.

Так что я почти отказался от фильтров. Моя следующая попытка состояла в том, чтобы создать собственный ActionBuilder, чтобы обернуть Actions, чтобы прикрепить Span к каждому запросу, и запустить Action с установленными локальными потоками. Такого рода работы, для тела действий. Тем не менее, я создаю Span позже, после того, как тело было проанализировано, и BodyParser по-прежнему не имеет к нему доступа. Это также довольно неудобно, так как теперь я должен изменить все свои контроллеры, чтобы использовать это для создания действий вместо объекта Action (а их много).

Существует ли какой-либо способ распространять данные вне диапазона (то есть, не являющиеся частью самого Содержимого тела) из анализатора тела или ранее в тело Действия. Или отправить данные из фильтра в код, выполненный аккумулятором?

1 Ответ

0 голосов
/ 02 мая 2018

Звучит так, будто вы уже попробовали следующее, но я все же хотел бы предоставить это в качестве ответа, просто чтобы четко указать, что вы пытались.

ActionTransformer позволяет безоговорочно добавлять информацию в запросы:

case class Span(id: String, message: String)

class RequestWithSpan[A](val span: Span, request: Request[A]) 
  extends WrappedRequest[A](request)

class SpanAction(val parser: BodyParser[AnyContent])(implicit val executionContext: ExecutionContext)
     extends ActionBuilder[RequestWithSpan, AnyContent] 
     with ActionTransformer[Request, RequestWithSpan] {  

  def transform[A](request: Request[A]) = Future.successful {
    val span = Span(
      id = request.headers("X-SPAN-ID"),
      message = request.headers("X-SPAN-MESSAGE")
    )
    new RequestWithSpan(span, request)
  }
}

class SomeController(
    ...
    someService: SomeService,
    spanAction: SpanAction) extends AbstractController(cc) with ... {

  def someEndpoint: Action[AnyContent] = {
    spanAction { implicit request =>
      implicit val span = request.span
      someService.doSomething(...)(span)
      Ok(span.toString)
    }
  }

}

Как вы заявили, теперь неудобно вводить SpanAction везде.

Кстати, идея прозрачного добавления информации о трассировке / отладке к запросам и ее распространения по всей системе - это действительно круто!

...