Определение bean-компонента RestTemplateBuilder приводит к тому, что распространение traceId через границы службы больше не работает.
Следующий код демонстрирует, что при включении bean-компонента в проектmicrometer-tracing
не будет правильно распространять s через границы службы.
Я публикую пример кода здесь, так как мой клиент запрещает мне делиться кодом через GitHub.
Создайте два проекта Spring Maven, демо-клиент и демо-сервер, используя приведенный ниже код, а затем запустите два скрипта, чтобы запустить микросервисы. Затем отправьте запрос GET наhttp://localhost:2048/tracer-response
и вы увидите в журналах демо-клиента, что s совпадают. Далее раскомментируйтеRestTemplateBuilder
боб вDemoClientApplication
и перезапустите скрипты. Повторите проверку, и вы увидите, чтоtraceId
s больше не совпадают.
Пожалуйста, сообщите, почему эта конфигурация больше не работает. Ранее он работал с Spring Boot 2.7.7 и Spring Cloud 2021.0.5. Если намерение команды Spring состоит в том, чтобы эта конфигурация больше не использовалась, и это указано в документации, то я приношу свои извинения за отсутствие этого. Если это не указано, то, на мой взгляд, это должно быть выделено как предупреждение, поскольку оно явно сводит на нет всю цель использования распределенной трассировки.
код демо-клиента
package com.example.democlient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@Slf4j
public class DemoClientApplication {
public static void main(String[] args) {
SpringApplication.run(DemoClientApplication.class, args);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
// Uncomment the bean definition below, and traceId propagation will no longer work, meaning the traceId
// values logged by demo-client and demo-server will not be the same value.
/* @Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder();
}*/
}
package com.example.democlient;
import io.micrometer.tracing.Tracer;
import jakarta.annotation.security.PermitAll;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class DemoClientController {
@Autowired RestTemplate restTemplate;
@Autowired Tracer tracer;
@PermitAll
@GetMapping(value = "/tracer-response", produces = MediaType.APPLICATION_JSON_VALUE)
public TracerResponse getClientResponse() {
log.info("Getting the tracer response from demo server...");
var clientTraceId = tracer.currentSpan().context().traceId();
var clientSpanId = tracer.currentSpan().context().spanId();
log.info(
"Here's the traceId and spanId before the call: {} and {}", clientTraceId, clientSpanId);
var serverTracerResponse =
restTemplate
.getForEntity("http://localhost:2049/tracer-response", TracerResponse.class)
.getBody();
var serverTraceId = serverTracerResponse.getTraceId();
var serverSpanId = serverTracerResponse.getSpanId();
log.info(
"Here's the traceId and spanId from the server: {} and {}", serverTraceId, serverSpanId);
log.info("Do the client and server traceIds match? {}", clientTraceId.equals(serverTraceId));
return serverTracerResponse;
}
}
package com.example.democlient;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class TracerResponse {
private String spanId;
private String traceId;
}
src/main/resources/application.yml
server:
port: 2048
spring:
application:
name: demo-client
src/main/resources/logback-spring.xml
пом.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-client</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
код демо-сервера
package com.example.demoserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoServerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServerApplication.class, args);
}
}
package com.example.demoserver;
import io.micrometer.tracing.Tracer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class DemoServerController {
@Autowired
Tracer tracer;
@GetMapping(value = "/tracer-response", produces = MediaType.APPLICATION_JSON_VALUE)
public TracerResponse getClientResponse() {
log.info("Getting the serverResponse...");
log.info("traceId: {} spanId: {}",tracer.currentSpan().context().traceId(),tracer.currentSpan().context().spanId());
var response = new TracerResponse();
response.setTraceId(tracer.currentSpan().context().traceId());
response.setSpanId(tracer.currentSpan().context().spanId());
return response;
}
}
package com.example.demoserver;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class TracerResponse {
private String traceId;
private String spanId;
}
src/main/resources/application.yml
server:
port: 2049
spring:
application:
name: demo-server
src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include
resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="springAppName"
source="spring.application.name"/>
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd, America/New_York} | %d{HH:mm:ss.SSS, America/New_York} | %-16.16thread | %-5.5p | %-40.40logger{40} | %-39.39(Trace: %X{traceId}) | %-22.22(Span: %X{spanId}) | %m%n"/>
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<logger name="com.example" level="DEBUG" additivity="false">
<appender-ref ref="console"/>
</logger>
<logger name="org.springframework" level="WARN"
additivity="false">
<appender-ref ref="console"/>
</logger>
<root level="WARN">
<appender-ref ref="console"/>
</root>
</configuration>
пом.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
скрипты для управления и запуска микросервисов
kill_demo_server.sh
#! /bin/bash
set -e
set -x
ps -ef | grep 'demo-server-0.0.1' | kill -9 $(awk 'NR==1{print $2}') 2>/dev/null;
build_deploy_demos.sh
#! /bin/bash
set -e
set -x
cd ~/repos/demo-server;
mvn clean install;
nohup java -jar target/demo-server-0.0.1-SNAPSHOT.jar &
cd ~/repos/demo-client;
mvn clean install;
java -jar target/demo-client-0.0.1-SNAPSHOT.jar