Search code examples
springopentracingjaeger

Configuring Jaeger in Spring application


I would like to configure Jaeger in my Spring application. Somehow I cannot find a proper way to do this. Almost all Spring-Jaeger-related documentation is for Spring Boot where most of the properties are auto configured. Here's my approach. Maven dependency:

    <dependency>
        <groupId>io.opentracing.contrib</groupId>
        <artifactId>opentracing-spring-jaeger-cloud-starter</artifactId>
        <version>1.0.3</version>
    </dependency>

Spring config for Jaeger:

@Configuration
public class JagerConfiguration {


    @Bean
    public io.opentracing.Tracer jaegerTracer() {
        Map<String, String> tags = new HashMap<>();
        tags.put(Constants.TRACER_HOSTNAME_TAG_KEY, "localhost");

        CompositeReporter reporter = new CompositeReporter(new LoggingReporter(), remoteReporter());


        return new Builder("myTestSpringApp")
                .withSampler(new ConstSampler(true))
                .withMetricsFactory(new InMemoryMetricsFactory())
                .withReporter(remoteReporter())
                .withTags(tags)
                .build();
    }

    @Bean
    public RemoteReporter remoteReporter() {
        return new RemoteReporter.Builder().withSender(new UdpSender("localhost", 6831, 0)).build();
    }
}

Jaeger is running locally in docker on port 6831.

docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest

Once my application starts, I noticed that application slows down considerably, I assume that is because of metrics logged heavily to console by LoggingReporter.

However, My Spring app does not show up in Jaeger UI. In the beginning I would like to trace my REST endpoints. Can someone point me in the right direction why my app is missing from UI and how I configure Jaeger properly? Is there perhaps a sample project with Spring+Jaeger that does not rely on outdated Jaeger?


Solution

  • If anyone else would like to set up Jaeger in spring project, here's what I did:

    Add dependencies to pom:

    <properties>
        <opentracing.spring.web.version>0.3.4</opentracing.spring.web.version>
        <opentracing.jdbc.version>0.0.12</opentracing.jdbc.version>
        <opentracing.spring.configuration.starter.version>0.1.0</opentracing.spring.configuration.starter.version>
        <opentracing.spring.jaeger.starter.version>0.2.2</opentracing.spring.jaeger.starter.version>
    </properties>
    
    <dependency>
        <groupId>io.opentracing.contrib</groupId>
        <artifactId>opentracing-spring-web-starter</artifactId>
        <version>${opentracing.spring.web.version}</version>
    </dependency>
    <dependency>
        <groupId>io.opentracing.contrib</groupId>
        <artifactId>opentracing-jdbc</artifactId>
        <version>${opentracing.jdbc.version}</version>
    </dependency>
    <dependency>
        <groupId>io.opentracing.contrib</groupId>
        <artifactId>opentracing-spring-tracer-configuration-starter</artifactId>
        <version>${opentracing.spring.configuration.starter.version}</version>
    </dependency>
    <dependency>
        <groupId>io.opentracing.contrib</groupId>
        <artifactId>opentracing-spring-jaeger-starter</artifactId>
        <version>${opentracing.spring.jaeger.starter.version}</version>
    </dependency>
    

    Set up you web.xml to register new tracing filter tracingFilter to intercept REST API:

    <filter>
        <filter-name>tracingFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
        <filter-name>tracingFilter</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>
    

    Register jaeger tracer in spring mvc:

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean class="io.opentracing.contrib.spring.web.interceptor.TracingHandlerInterceptor">
                <constructor-arg ref="jaegerTracer" />
            </bean>
        </mvc:interceptor>
    </mvc:interceptors>
    

    Set up the tracingFilter bean we described in web.xml:

    import io.opentracing.Tracer;
    import io.opentracing.contrib.web.servlet.filter.TracingFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration
    public class JaegerFilterConfiguration {
    
        @Bean
        public TracingFilter tracingFilter(Tracer tracer) {
            return new TracingFilter(tracer);
        }
    }
    

    Finally define jaeger tracer spring configuration:

    import io.jaegertracing.internal.JaegerTracer;
    import io.jaegertracing.internal.metrics.NoopMetricsFactory;
    import io.jaegertracing.internal.reporters.RemoteReporter;
    import io.jaegertracing.internal.reporters.RemoteReporter.Builder;
    import io.jaegertracing.internal.samplers.ProbabilisticSampler;
    import io.jaegertracing.thrift.internal.senders.UdpSender;
    import io.opentracing.Tracer;
    import io.opentracing.util.GlobalTracer;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.context.event.ContextRefreshedEvent;
    
    
    @Configuration
    public class JaegerConfiguration implements ApplicationListener<ContextRefreshedEvent> {
    
    
        private static final int JAEGER_PORT = 6831;
        private static final String JAEGER_HOST = "localhost";
        private static final String JAEGER_SERVICE_NAME = "my-awesome-jaeger";
        private static final double SAMPLING_RATE = 0.5;
        @Autowired
        private Tracer tracer;
    
        @Bean
        @Primary
        public Tracer jaegerTracer(RemoteReporter remoteReporter) {
            return new JaegerTracer.Builder(JAEGER_SERVICE_NAME)
                    .withReporter(remoteReporter)
                    .withMetricsFactory(new NoopMetricsFactory()).withSampler(new ProbabilisticSampler(SAMPLING_RATE))
                    .build();
        }
    
        @Bean
        public RemoteReporter remoteReporter() {
            return new Builder().withSender(new UdpSender(JAEGER_HOST, JAEGER_PORT, 0)).build();
        }
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            if (!GlobalTracer.isRegistered()) {
                GlobalTracer.register(tracer);
            }
        }
    }