【问题标题】:Getting reference to context in Spring Reactor在 Spring Reactor 中获取对上下文的引用
【发布时间】:2018-06-18 21:41:57
【问题描述】:

我正在使用 Spring projectreactor reactor-core 3.1.8.RELEASE。我正在为我的微服务实现一个日志框架以具有 JSON 审计日志,因此使用上下文来存储某些字段,例如用户 ID、协作 ID、组件名称以及在请求生命周期中常见的一些其他字段。由于Threadlocal 不能用于响应式服务来存储这些元素,因此我必须使用上下文。但是获得对上下文的参考显然是非常困难的。我可以通过doOnEach 函数调用从信号中获取对上下文的引用,仅此而已。如果我使用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 函数调用,我们可以通过该函数获取 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") }

谢谢!

【问题讨论】:

  • 已经有很多关于这方面的文档:projectreactor.io/docs/core/release/reference/#context - 你能用代码 sn-ps 编辑你的问题以显示你想要实现的目标以及如何实现吗?
  • 谢谢。上面的链接解释了一旦你有了上下文对象你可以做什么。但我看到 doOnEach 是唯一一个引用上下文的函数,我可以用它来获取和放入键值对。我已将原始帖子编辑为具有代码 sn-ps。

标签: spring project-reactor


【解决方案1】:

您可以执行以下操作:

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

}

不太好,希望最终能被Logging框架改进,自动注入上下文。

【讨论】:

    猜你喜欢
    • 2018-09-09
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    • 2011-04-04
    • 2019-06-15
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多