Spring Cloud Sleuth 如何在 Webflux ouf of the box 中传播 MDC 上下文,以便在不同的线程中记录其内容?

问题描述 投票:0回答:1

我想知道Spring Cloud Sleuth如何在线程之间传播MDC上下文,使MDC参数在每个线程中都可用。

我读过这篇文章 https:/simonbasle.github.io201802contextual-logging-with-reactor-context-and-mdc。 建议使用订阅者上下文在线程之间传播MDC状态。

我需要对一些请求头的其他parars做类似的事情,所以我创建了将其放入当前线程的MDC中,并将其存储在subscriber上下文中。然而下一个恢复执行的线程却没有它。不知何故,我应该在新的线程中使用上下文中的值再次调用MDC,但如何调用?

@Slf4j
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ReactiveRequestCorrelationFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String principal = exchange.getRequest().getHeaders().getFirst("principal-header");
        MDC.put("principal", principal);
        return chain.filter(exchange)
                .subscriberContext(Context.of("principal", principal))
                .doOnTerminate(MDC::clear);
    }

}

看看这个控制器映射。

    @GetMapping(value = "/v1/departments", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<Department> getDepartments() {
        log.info("getDepartaments");
        return webClient.get().uri("http://someService:8080/api/v1/departamentosFoo").retrieve().bodyToFlux(Departments.class)
                .doOnNext(dep -> log.info("found department {}", dep));
    }

它产生了这样的日志

logging.pattern.console="%magenta([%thread]) [%X{traceId}] [%X{spanId}] [%X{principal}]  - %m%n"
[boundedElastic-2] [d0a916db8be0cbf7] [d0a916db8be0cbf7] []  - getDepartments
[boundedElastic-2] [d0a916db8be0cbf7] [fb2367685db70201] []  - found department Department(id=1, nombre=dep, fechaAlta=Fri Apr 24 14:16:20 CEST 2020, staff=1, tag=, empresa=true)
[reactor-http-nio-3] [d0a916db8be0cbf7] [d0a916db8be0cbf7] []  - found department Department(id=1, nombre=dep, fechaAlta=Fri Apr 24 14:16:20 CEST 2020, staff=1, tag=, empresa=true)

该请求从一个reactor-http-nio线程开始,然后被转到boundedElastic-2。如你所见,traceId和spanId的值都显示出来了,但没有我在过滤器中放的那个。Sleuth是如何将它的上下文(traceId spanId)传播到其他线程的?

spring-boot spring-cloud spring-webflux project-reactor spring-cloud-sleuth
1个回答
0
投票

他们使用Reactor Context以及Reactor Hooks.相关代码来自spring-cloud-sleuth。链接

其他一些可能有用的链接。


2
投票

根据Martin在回答中提供的信息,我做了一些研究,得出如下结论。

更新了过滤器:

@Slf4j
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE + 6)
public class ReactiveRequestCorrelationFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return chain.filter(exchange)
                .doOnSubscribe(s -> {
                    String principal = exchange.getRequest().getHeaders().getFirst("principal-header");
                    ExtraFieldPropagation.set("principal", principal);
                });
    }

}

application.yml

spring:
  sleuth:
    log:
      slf4j:
        whitelisted-mdc-keys: principal
    baggage-keys: principal

有了这个,我的自定义字段开始在日志中显示出来,由Sleuth负责设置它并从MDC中清除它。

[boundedElastic-2] [fadba73bf6447d02] [fadba73bf6447d02] [myprincipal] getDepartaments

2
投票

你不需要任何定制就能让它工作。要传播自定义的HTTP头信息,只需要告诉Sleuth它们的情况。

#The one is on by default
spring.sleuth.log.slf4j.enabled=true

spring.sleuth.propagation-keys=principal-header
spring.sleuth.log.slf4j.whitelisted-mdc-keys=principal-header

(我用的是properties版本,但同样的事情也适用于yaml)

然后在你的logback配置中使用

[%X{principal-header}]

就这样吧!

N.B.就我个人而言,我更倾向于去掉那个 "我 "字。-header 位从头名。

© www.soinside.com 2019 - 2024. All rights reserved.