【发布时间】:2021-02-28 11:51:20
【问题描述】:
我想为每个请求生成唯一的 traceId 并将其传递给所有服务。在 Spring MVC 中,使用 MDC 上下文并将 traceId 放在 header 中相当容易,但在响应式堆栈中,由于 ThreadLocal,它根本不起作用。
一般来说,我想用单个 traceId 记录我拥有的每个服务的每个请求和响应,它可以识别整个系统中的特定操作。
我尝试根据文章创建自定义过滤器:https://azizulhaq-ananto.medium.com/how-to-handle-logs-and-tracing-in-spring-webflux-and-microservices-a0b45adc4610,但它似乎不起作用。
我目前的解决方案只记录响应和 traceId 在发出请求后丢失,所以没有响应。
让我们尝试假设有两个服务:service1 和 service2。下面我试图勾勒出它应该如何工作。
它应该如何工作
-
client->service1- service1 应该生成 traceId 并记录请求 -
service1->service2- service2 应该从请求中获取 traceId,然后记录请求 -
service1service2 - 经过一些计算,service2 应该记录响应并将响应返回给 service1 -
clientservice1 - 最后 service1 应该记录响应(仍然具有相同的 traceId)并将响应返回给客户端
实际工作原理
-
client->service1- 日志中没有任何内容 -
service1->service2- 日志中没有任何内容 -
service1service2 - service2 正在正确记录并向 service1 返回响应 -
clientservice1 - service1 正在记录响应(但没有 traceId)
这是我的方法
@Component
public class TraceIdFilter implements WebFilter {
private static final Logger log = LoggerFactory.getLogger(TraceIdFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
Map<String, String> headers = exchange.getRequest().getHeaders().toSingleValueMap();
return Mono.fromCallable(() -> {
final long startTime = System.currentTimeMillis();
return new ServerWebExchangeDecorator(exchange) {
@Override
public ServerHttpRequest getRequest() {
return new RequestLoggingInterceptor(super.getRequest(), false);
}
@Override
public ServerHttpResponse getResponse() {
return new ResponseLoggingInterceptor(super.getResponse(), startTime, false);
}
};
}).contextWrite(context -> {
var traceId = "";
if (headers.containsKey("X-B3-TRACEID")) {
traceId = headers.get("X-B3-TRACEID");
MDC.put("X-B3-TraceId", traceId);
} else if (!exchange.getRequest().getURI().getPath().contains("/actuator")) {
traceId = UUID.randomUUID().toString();
MDC.put("X-B3-TraceId", traceId);
}
Context contextTmp = context.put("X-B3-TraceId", traceId);
exchange.getAttributes().put("X-B3-TraceId", traceId);
return contextTmp;
}).flatMap(chain::filter);
}
}
Github:https://github.com/Faelivrinx/kotlin-spring-boot
有任何现有的解决方案吗?
【问题讨论】:
-
it's seems to not working请包括预期行为、当前行为以及这些行为有何不同。 -
我已经编辑了主帖并添加了解释
-
你考虑过使用
spring-cloud-sleuth吗?这已经提供了一个WebFilter,它将创建和/或传播traceId。 -
好主意,我来看看它是如何工作的。是否有任何内置配置可以将 traceId 提供给 WebClient?
标签: spring-boot spring-webflux trace spring-cloud-sleuth