Получение ссылки на контекст в Spring Reactor
Я использую Spring Projectreactor реактор с активной зоной 3.1.8.RELEASE. Я внедряю каркас журналирования для моего микросервиса, чтобы иметь журналы аудита JSON, поэтому использовал контекст для хранения определенных полей, таких как идентификатор пользователя, идентификатор совместной работы, имя компонента и несколько других полей, которые являются общими для жизненного цикла запроса. поскольку Threadlocal
не может использоваться в реактивных сервисах для хранения этих элементов, я должен использовать контекст. Но получить ссылку на контекст, по-видимому, очень сложно. Я могу получить ссылку на контекст из Сигнала через doOnEach
вызов функции и все тут. Если я использую doOnEach
он вызывается для всех типов сигналов, и я не могу выделить ошибки, успех и т. д. Более того, если между ними возникает ошибка, то все последующие doOnEach
в любом случае вызывается, поэтому журналы повторяются с несколькими onError
типы журналов.
Существует очень ограниченная документация относительно того, как получить ссылку на объект контекста в реакторе Spring. Приветствуется любая помощь, касающаяся лучшего способа создания журналов аудита, в которых есть идентификаторы совместной работы и другие идентификаторы, специфичные для запросов, которые хранятся и распространяются через вызовы функций и внешние вызовы.
Фрагменты кода. В WebFilter я устанавливаю несколько пар ключ-значение следующим образом:
override fun filter(exchange: ServerWebExchange, filterChain: WebFilterChain): Mono<Void> {
// add the context variables at the end of the chain as the context moves from
// downstream to upstream.
return filterChain.filter(exchange)
.subscriberContext { context ->
var ctx = context.put(RestRequestInfo::class.java, restRequestInfo(exchange))
ctx = ctx.put(COLLABORATION_ID, UUID.randomUUID().toString())
ctx=ctx.put(COMPONENT_NAME, "sample-component-name")
ctx=ctx.put(USER_NAME, "POSTMAN")
ctx
}
}
Затем я хочу использовать пары ключ-значение, добавленные выше, во всех последующих журналах, чтобы агрегаторы журналов, такие как Splunk, могли получать все журналы JSON, связанные с этим конкретным запросом, на основе идентификатора совместной работы. Прямо сейчас единственный способ вывести значения из контекста - это вызов функции doOnEach, где мы получаем дескриптор SIgnal, через который мы получаем дескриптор контекста. Но все doOnEach вызывается во время каждого события, независимо от того, был ли каждый вызов функции успешным или неудачным
return Mono.just(request)
.doOnEach(**Code to log with context data**)
.map(RequestValidations::validateRequest)
.doOnEach(**Code to log with context data**)
.map(RequestValidations::buildRequest)
.map(RequestValidations::validateQueryParameters)
.doOnEach(**Code to log with context data**)
.flatMap(coverageSummariesGateway::getCoverageSummaries)
.doOnEach(**Code to log with context data**)
.map({ coverageSummaries ->
getCoverageSummariesResponse(coverageSummaries, serviceReferenceId) })
.doOnEach(**Code to log with context data**)
.flatMap(this::renderSuccess)
.doOnEach(**Code to log with context data**)
.doOnError { logger.info("ERROR OCCURRED") }
Спасибо!
0 ответов
Вы можете сделать что-то вроде следующего:
return Mono.just(request)
.doOnEach(**Code to log with context data**)
.flatMap( r -> withMDC(r, RequestValidations::validateRequest))
Следующий метод заполнит диагностический контекст сопоставления (MDC), чтобы он был автоматически в ваших журналах (зависит от вашего шаблона ведения журнала). Например, логбэк имеет%X{traceId}
где traceId
ключ к tracingContext
карта.
public static <T, R> Mono<R> withMDC(T value, Function<T, Mono<R>> f) {
return Mono.subscriberContext()
.flatMap( ctx -> {
Optional<Map> tracingContext = ctx.getOrEmpty("tracing-context-key");
if (tracingContext.isPresent()) {
try {
MDC.setContextMap(tracingContext.get());
return f.apply(value);
} finally {
MDC.clear();
}
} else{
return f.apply(value);
}
});
}
Это не совсем хорошо, надеюсь, что в конечном итоге это будет улучшено фреймворками ведения журналов, и контекст будет внедрен автоматически.