spring - 在 Spring Reactor 中获取上下文的引用

标签 spring project-reactor

我正在使用 Spring 项目reactorreactor-core 3.1.8.RELEASE。我正在为我的微服务实现一个具有 JSON 审核日志的日志记录框架,因此使用上下文来存储某些字段,例如用户 ID、协作 ID、组件名称以及请求生命周期中常见的其他一些字段。由于 Threadlocal 无法在响应式(Reactive)服务中使用来存储这些元素,因此我必须使用上下文。但获得上下文的引用显然是非常困难的。我可以通过 doOnEach 函数调用从 Signal 获取上下文的引用,仅此而已。如果我使用 doOnEach,它会被所有信号类型调用,并且我无法隔离错误、成功等。此外,如果中间发生错误,那么所有后续的 doOnEach 都会被调用,因此日志会以多种 onError 日志类型重复。

关于如何在 Spring Reactor 中获取上下文对象的引用的文档非常有限。任何有关生成审计日志的更好方法的帮助,该日志具有跨函数调用和外部调用存储和传播的协作 ID 和其他请求特定 ID。

代码片段 - 在 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 等日志聚合器可以根据协作 ID 获取与此特定请求关联的所有 JSON 日志。目前,从上下文中获取值的唯一方法是通过 doOnEach 函数调用,在该函数中我们获取信号句柄,通过该句柄获取上下文句柄。但所有 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") }

谢谢!

最佳答案

您可以执行以下操作:

return Mono.just(request)
            .doOnEach(**Code to log with context data**)
            .flatMap( r -> withMDC(r, RequestValidations::validateRequest))

以下方法将填充映射诊断上下文 (MDC),以便您将其自动记录在日志中(取决于您的日志记录模式)。例如。 logback 有 %X{traceId},其中 traceIdtracingContext 映射中的键。

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

}

这不太好,希望它最终能通过日志框架改进,并且上下文会自动注入(inject)。

关于spring - 在 Spring Reactor 中获取上下文的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50917869/

相关文章:

java - 使用@DataJpaTest 时未配置 JdbcTemplate

java - 如何使用 spring boot 动态创建 imap 接收器适配器?

Spring数据、JPA和Hibernate : why does my object gets saved with the save statement removed?

java - 如何将通量链接到另一个通量/单声道并施加另一个背压?

java - Reactor Mono 发布到多个方法

java - 如何使用 Spring Data Redis Repositories 构建动态查询?

java - 如何在 Spring Boot 测试中获取正在运行的服务器端口?

java - 将对象写入 Flux

java - 有条件地将 Mono 与 Flux 结合起来

java - 如何从异步值创建千分尺?