使用 Feign 生成器请求不会将 trace-id、span-id 发送到 child 客户端,但使用 rest 模板会在 child 客户端上显示所有 headers
Using Feign builder requests doesn't send trace-id, span-id to child clients but using rest template is showing all headers on child clients
我正在使用 Feign Builder 发出顺序请求。请求的标题中没有 x-b3-traceid,x-b3-spanid ..。这就是为什么我最后一个客户端的日志出现在 zipkin 上的原因。
我使用spring boot 2.4.2,spring cloud 2020.0.0,feign-core 10.10.1,feign-okhttp 10.10.1。我试过 spring-cloud-openfeign 并取得了想要的结果。但我不想使用这个库。在这里使用 Feign Builder 和 Rest Template 时有请求。我在 zipkin 上没有看到相同的日志。
我的 Client1 应用程序。我正在发送请求 http://localhost:8082/
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
@RestController
public class SampleController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Autowired
private Client client;
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
@GetMapping("/hello/feignBuilder")
public String sayHelloFeignBuilder(HttpServletRequest httpServletRequest){
logger.info("Send to request client2");
Client2Feign client2Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client2Feign.class, "http://localhost:8082/");
return client2Feign.sayHelloFeignBuilder();
}
@GetMapping("/hello/say")
public String sayHelloFeignBuilder1(){
return "Hello";
}
@GetMapping("/hello/rest")
public String sayHelloRest(){
System.out.println(tracer.currentSpan());
logger.info("Inside rest 1");
String baseUrl = "http://localhost:8082/sayHelloRest";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client2 is " + response);
return response;
}
}
这是我的 client1 应用程序的 yml。我在 client2 和 clint3 的其他客户端应用程序上使用相同的 yml conf。仅更改端口和应用名称。
server:
port: 8081
spring:
application:
name: euraka-client1
zipkin:
enabled: true
service.name: euraka-client1
sender.type: web
base-url: http://localhost:9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
instance:
preferIpAddress: true
这是我的 Feign at Client2 应用程序。
import feign.RequestLine;
public interface Client2Feign {
@RequestLine("GET /sayHelloBuilder")
String sayHelloFeignBuilder();
}
这里是ClientFeign2的实现。
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
public interface FeignBuilderController {
@GetMapping("/sayHelloBuilder")
String sayHelloBuilder(HttpServletRequest httpServletRequest);
@GetMapping("/sayHelloRest")
String sayHelloRest(HttpServletRequest httpServletRequest);
}
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign.Client3Feign;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
@RestController
public class FeignBuilderControllerImpl implements FeignBuilderController{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Autowired
private Client client;
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
@Override
public String sayHelloBuilder(HttpServletRequest httpServletRequest) {
logger.info("Send to request client3");
Client3Feign client3Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client3Feign.class, "http://localhost:8083/");
return client3Feign.sayHelloFeignBuilder3();
}
@Override
public String sayHelloRest(HttpServletRequest httpServletRequest) {
logger.info("Inside rest 2");
String baseUrl = "http://localhost:8083/sayHelloRestClient3";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client3 is " + response);
return response;
}
这是我的 Feign at Client3 应用程序。
import feign.RequestLine;
public interface Client3Feign {
@RequestLine("GET /sayHelloBuilderClient3")
String sayHelloFeignBuilder3();
}
这里是Client3 Feign的实现。
import javax.servlet.http.HttpServletRequest;
public interface FeignController3 {
@GetMapping("/sayHelloBuilderClient3")
String sayHello3(HttpServletRequest httpServletRequest);
@GetMapping("/sayHelloRestClient3")
String sayHelloRest3(HttpServletRequest httpServletRequest);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping
public class FeignController3Impl implements FeignController3 {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public String sayHello3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using FeignClientBuilder";
}
@Override
public String sayHelloRest3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using RestClient";
}
}
pom.xml 来自 client3,我在 client2/pom 使用 client3,与 client1 相同。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>oguzhan.example</groupId>
<artifactId>client3</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
diff-feign-rest-image
feign-zipkin-img
feign-request-img
rstlet-rest-tmplte-img
rest-zipkin-img
问题可能与您通过 Feign.builder()
工厂方法手动创建 Feign 构建器有关。我们无法检测该调用。您应该创建一个 bean(通过 SleuthFeignBuilder.builder
)并将其注入到您的代码中。
我正在使用 Feign Builder 发出顺序请求。请求的标题中没有 x-b3-traceid,x-b3-spanid ..。这就是为什么我最后一个客户端的日志出现在 zipkin 上的原因。
我使用spring boot 2.4.2,spring cloud 2020.0.0,feign-core 10.10.1,feign-okhttp 10.10.1。我试过 spring-cloud-openfeign 并取得了想要的结果。但我不想使用这个库。在这里使用 Feign Builder 和 Rest Template 时有请求。我在 zipkin 上没有看到相同的日志。
我的 Client1 应用程序。我正在发送请求 http://localhost:8082/
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
@RestController
public class SampleController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Autowired
private Client client;
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
@GetMapping("/hello/feignBuilder")
public String sayHelloFeignBuilder(HttpServletRequest httpServletRequest){
logger.info("Send to request client2");
Client2Feign client2Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client2Feign.class, "http://localhost:8082/");
return client2Feign.sayHelloFeignBuilder();
}
@GetMapping("/hello/say")
public String sayHelloFeignBuilder1(){
return "Hello";
}
@GetMapping("/hello/rest")
public String sayHelloRest(){
System.out.println(tracer.currentSpan());
logger.info("Inside rest 1");
String baseUrl = "http://localhost:8082/sayHelloRest";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client2 is " + response);
return response;
}
}
这是我的 client1 应用程序的 yml。我在 client2 和 clint3 的其他客户端应用程序上使用相同的 yml conf。仅更改端口和应用名称。
server:
port: 8081
spring:
application:
name: euraka-client1
zipkin:
enabled: true
service.name: euraka-client1
sender.type: web
base-url: http://localhost:9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
instance:
preferIpAddress: true
这是我的 Feign at Client2 应用程序。
import feign.RequestLine;
public interface Client2Feign {
@RequestLine("GET /sayHelloBuilder")
String sayHelloFeignBuilder();
}
这里是ClientFeign2的实现。
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
public interface FeignBuilderController {
@GetMapping("/sayHelloBuilder")
String sayHelloBuilder(HttpServletRequest httpServletRequest);
@GetMapping("/sayHelloRest")
String sayHelloRest(HttpServletRequest httpServletRequest);
}
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign.Client3Feign;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
@RestController
public class FeignBuilderControllerImpl implements FeignBuilderController{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Autowired
private Client client;
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
@Override
public String sayHelloBuilder(HttpServletRequest httpServletRequest) {
logger.info("Send to request client3");
Client3Feign client3Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client3Feign.class, "http://localhost:8083/");
return client3Feign.sayHelloFeignBuilder3();
}
@Override
public String sayHelloRest(HttpServletRequest httpServletRequest) {
logger.info("Inside rest 2");
String baseUrl = "http://localhost:8083/sayHelloRestClient3";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client3 is " + response);
return response;
}
这是我的 Feign at Client3 应用程序。
import feign.RequestLine;
public interface Client3Feign {
@RequestLine("GET /sayHelloBuilderClient3")
String sayHelloFeignBuilder3();
}
这里是Client3 Feign的实现。
import javax.servlet.http.HttpServletRequest;
public interface FeignController3 {
@GetMapping("/sayHelloBuilderClient3")
String sayHello3(HttpServletRequest httpServletRequest);
@GetMapping("/sayHelloRestClient3")
String sayHelloRest3(HttpServletRequest httpServletRequest);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping
public class FeignController3Impl implements FeignController3 {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public String sayHello3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using FeignClientBuilder";
}
@Override
public String sayHelloRest3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using RestClient";
}
}
pom.xml 来自 client3,我在 client2/pom 使用 client3,与 client1 相同。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>oguzhan.example</groupId>
<artifactId>client3</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
diff-feign-rest-image
feign-zipkin-img
feign-request-img
rstlet-rest-tmplte-img
rest-zipkin-img
问题可能与您通过 Feign.builder()
工厂方法手动创建 Feign 构建器有关。我们无法检测该调用。您应该创建一个 bean(通过 SleuthFeignBuilder.builder
)并将其注入到您的代码中。