繁体   English   中英

在使用带有新关键字的 resttemplate 进行 API 调用时,无法将 Sleuth traceid 和 spanid 传递给下游服务

[英]Not able to pass Sleuth traceid and spanid to downstream services while making API calls using resttemplate with new keyword

目前,我正在将 Sleuth 集成到我们现有的微服务中以增强日志记录机制。 MS 使用 Spring Boot 2.5.6 和 Spring Cloud 2020.0.6 构建(已解决为 Spring Cloud Sleuth 3.0)。

我试图解决的挑战是在进行出站 API 调用时,我们使用 new() 关键字创建 RestTemplate,而不是将 RestTemplate 作为 Bean 管理。 不幸的是,我们无权更改使用 resttemplate 作为 Bean 的方法,以使 Sleuth 和 Brave 工具无缝工作(以避免在应用程序中引入任何重大更改)以将 traceid 传播到下游日志(如前所述在官方文档中)。 因此,MS1 和 MS2 日志中的 traceid 不同,这使得跟踪变得困难。

正如我从官方文档中了解到的那样,Brave 将拦截器注册为喜欢 LazyTraceClientHttpRequestInterceptor 和 TracingClientHttpRequestInterceptor 以将 X-B3-Traceid、X-B3-SpanId 等标头添加到出站请求中,我尝试做类似的事情。

这是我的自定义拦截器的代码:

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
 
@Component
public class RequestResponseLoggingInterceptor implements ClientHttpRequestInterceptor {
    
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    
    private Tracer tracer;
    
    RequestResponseLoggingInterceptor(Tracer tracer){
        this.tracer = tracer;
    }
  
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException 
    {
        Span span = tracer.currentSpan();
        
        HttpHeaders headers = new HttpHeaders();
        headers.set("X-B3-Traceid", span.context().traceId());
        headers.set("X-B3-SpanId", span.context().spanId());
        headers.set("X-B3-ParentSpanId", span.context().parentId());
        request.getHeaders().addAll(headers);
        
        ClientHttpResponse response = execution.execute(request, body);
        return response;
    }
}

在我的 controller class 中,我已经自动连接了这个拦截器:

@Autowired
private RequestResponseLoggingInterceptor interceptor;

并使用此拦截器进行 resttemplate 调用,如下所示:

RestTemplate restTemplate = new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList(interceptor));
        ResponseEntity<ProductSale> responseEntity = restTemplate.getForEntity(
                "http://localhost:8000/product-service/pname/{pname}/cost/{cost}/qty/{qty}", ProductSale.class,
                uriVariables);
        ProductSale sales = responseEntity.getBody();

当我比较这个 API 调用的 MS1 和 MS2 日志时,traceid 是不同的。

  • 据我了解,MS2 应该寻找 X-B3 字段来生成
    日志的 traceid,但它没有使用请求 header 中发送的 traceid。
  • 而且,在通常的设置中,MS2 的跨度应该已经注入到 MS1 内的标头中
    拨打电话。 但是当我在拦截器中调试和检查 Trace id 和 SpanId 时,它们是相同的。

谁能帮我我在这里做错了什么? 以及如何通过使用 New() 关键字创建 RestTemplate 来实现向下游服务的 traceid 传播。

我和 Sleuth 合作的不多,但我对每次创建一个新的 RestTemplate 都有很大的怀疑。

尝试使用 singleton scope 将其定义为 bean,然后自动装配 RestTemplate。

您需要将TracingClientHttpRequestInterceptor bean 注入到您的 rest 模板中,它将负责传递跟踪上下文。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM