Распространение контекста через анализатор и тело действия в игровой среде
Я распространил информацию трассировки, которая передается с запросами между службами в заголовках HTTP (специально для opentracing).
Я хотел бы, чтобы эта информация была доступна везде, чтобы я мог включить идентификатор трассировки в журналы, распространяться на последующие запросы и т. Д.
Итак, я хочу разобрать заголовки, чтобы создать Span
перед обработкой запроса сделайте диапазон доступным для кода обработки, а затем выполните некоторую очистку после обработки запроса.
вещи, которые я пробовал:
Сначала казалось, что Фильтр будет правильным подходом, но с этим есть несколько проблем:
- Установка локального хранилища потока при вызове следующего действия не очень помогает, потому что обычно большая часть работы выполняется во время или после Аккумулятора, который он возвращает. В этот момент локальное хранилище потока было сброшено.
- насколько я могу судить, нет никакого способа обернуть
Accumulator
так что этапы накопления обернуты в контекст с локальным набором потока. Лучшее, что я смог сделать, это использоватьAccumulator.source
для накопителя я возвращаюсь, а затем использую запустить вложенный аккумулятор действий с источником из него и пользовательский материализатор, который упаковывает все методы для установки локальных потоков. Но это все еще не работает, я думаю, потому что материализатор отправляет в другой поток. Я настроил диспетчер по умолчанию для akka, чтобы отслеживать эти локальные потоки, но в этом случае материализатор, кажется, обходит его. - Нет способа прикрепить произвольные данные к RequestHeader, теги работают только для строк. И даже если бы это было так, мне пришлось бы поменять все свои контроллеры, чтобы прочитать их.
Так что я почти отказался от фильтров. Моя следующая попытка состояла в том, чтобы создать собственный ActionBuilder, чтобы обернуть Actions, чтобы прикрепить Span к каждому запросу, и запустить Action с установленными локальными потоками. Такого рода работы, для тела действий. Тем не менее, я создаю Span позже, после того, как тело было проанализировано, а BodyParser по-прежнему не имеет к нему доступа. Это также довольно неудобно, так как теперь я должен изменить все свои контроллеры, чтобы использовать это для создания действий вместо Action
объект (а их много).
Существует ли какой-либо способ распространения данных вне диапазона (то есть, не являющихся частью самого Содержимого тела) из анализатора тела или более ранних версий в тело действия. Или отправить данные из фильтра в код, выполняемый аккумулятором?
1 ответ
Похоже, вы уже попробовали следующее, но я все же хотел бы предоставить это в качестве ответа, просто чтобы четко указать, что вы пытались.
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
везде.
Кстати, идея прозрачного добавления информации о трассировке / отладке к запросам и ее просачивания по всей системе - это действительно круто!