Search code examples
javaspring-bootelasticsearchspring-data-elasticsearchjaeger

Jaeger does not span elasticsearch requests


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?


Solution

  • 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));
          }
        };
      }
      }