当前位置: 首页 > 知识库问答 >
问题:

Spring反应器中的上下文参考

董良策
2023-03-14

我用的是Spring项目Reactor堆芯3.1.8。释放我正在为我的微服务实现一个日志框架,使其具有JSON审计日志,因此使用上下文来存储某些字段,如userID、collaboration ID、component Name和其他几个在请求生命周期中常见的字段。由于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函数调用,在这里,我们得到信号的句柄,通过它我们得到上下文的句柄。但所有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") }

非常感谢。

共有1个答案

谢骏奇
2023-03-14

你可以这样做:

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

下面的方法将填充mapping diagnostic context(MDC),以便您的日志中自动包含它(取决于您的日志模式)。例如,logback有%X{traceId}其中traceIdtracingContext映射中的一个键。

java prettyprint-override">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);
                    }
               });

}

这不是很好,希望它最终能通过日志框架得到改进,并自动注入上下文。

 类似资料:
  • 问题内容: 我正在使用通过上下文传递的函数。 现在我用。这可行。 如果我需要来自两个不同父组件的函数,该怎么办? 问题答案: 您仍然可以通过16.3 Context API来使用子级功能消费者节点,这是React文档建议的做法: 要在组件的上下文中使用函数,通常将组件包装在HOC中,以便将上下文作为prop传递: 如果您正在运行React 16.8+,则还可以使用钩子更干净地执行此操作,而无需使用

  • 问题内容: 问候 , 有什么方法可以将值从web.xml context-param转换为Spring上下文吗? 例如,我将web.xml中的值定义为: 我想将该值分配给bean属性为: 提前致谢? 问题答案: 是的- 本文介绍了详细信息。简而言之,您需要: 然后使用以下属性: 或搭配

  • 我已经插入反应路由器4到我的反应创建应用程序和运行我得到以下错误: 我在用react-router@4.2.0,并对路由器作出反应-dom@4.2.2 我已确保我的

  • 我在Spring Boot应用程序中使用React Axios进行API调用。 我的应用程序上下文路径是test 当我在浏览器中启动应用程序时,http://localhost:8080/test,反应页面呈现。在页面呈现中,我正在调用服务 因此,预期调用应为http://localhost:8080/test/api/events,因为test是上下文根。但是,API调用中添加了测试。 只是打电

  • 我多年来一直在使用Spring MVC,我试图理解与Spring Boot的一些关键区别。 你能帮我确认一下吗?或者让我明白我在这里遗漏了什么?

  • 我还尝试了一个flatMap()和一个mono.subscriberContext(),但我不确定如何正确地插入过滤器(特别是在错误的情况下)。 实现这一目标的最佳方法是什么?