I have a Reactive SpringBoot web application. This application uses Spring-Data-Elasticsearch to request data from Elasticsearch. The application is configured to use Jaeger tracer for API-requests monitoring.
Jaeger works ok except for Elasticsearch requests - they do not appear in nested spans of the trace. Any other web requests are present.
I have the following gradle.build
configuration:
gradle.build:
springBootVersion = '2.4.2'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-reactor-netty'
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
implementation 'io.opentracing.contrib:opentracing-spring-jaeger-web-starter:2.0.3'
implementation 'io.opentracing.contrib:opentracing-elasticsearch7-client:0.1.2'
application.yml
spring:
data:
elasticsearch:
client:
reactive:
endpoints:
- localhost:9200
A jaeger run command:
docker run -d --name jaeger -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 14250:14250 -p 9411:9411 jaegertracing/all-in-one:latest
Does anybody have any thoughts on why Jaeger does not span elasticsearch requests?
Here is a solution that works. We need to
reuse existed beans Tracer
and spanDecorators
add a Trace filter into ES web client configuration:
@Configuration
@RequiredArgsConstructor
public class ElasticSearchClientConfiguration implements ErrorLogging {
private final ReactiveElasticsearchRestClientProperties properties;
private final Tracer tracer;
private final List<WebClientSpanDecorator> spanDecorators;
@Bean
public ClientConfiguration clientConfiguration() {
ClientConfiguration.MaybeSecureClientConfigurationBuilder builder =
ClientConfiguration.builder().connectedTo(properties.getEndpoints().toArray(new String[0]));
configureWebClient(builder);
return builder.build();
}
private void configureWebClient(ClientConfiguration.TerminalClientConfigurationBuilder builder) {
builder.withWebClientConfigurer(
webClient ->
webClient
.mutate()
.filters(addTraceExchangeFilterFunctionIfNotPresent())
.build());
}
private Consumer<List<ExchangeFilterFunction>> addTraceExchangeFilterFunctionIfNotPresent() {
return functions -> {
if (functions.stream()
.noneMatch(function -> function instanceof TracingExchangeFilterFunction)) {
functions.add(new TracingExchangeFilterFunction(tracer, spanDecorators));
}
};
}
}