我想知道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)传播到其他线程的?
他们使用Reactor Context以及Reactor Hooks.相关代码来自spring-cloud-sleuth。链接
其他一些可能有用的链接。
根据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
你不需要任何定制就能让它工作。要传播自定义的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
位从头名。