Hot questions for Spring Cloud Sleuth

Top 10 Java Open Source / Spring / Spring Cloud Sleuth

Question:

Sleuth is not sending the trace information to Zipkin, even though Zipkin is running fine. I am using Spring 1.5.8.RELEASE, spring cloud Dalston.SR4 and I have added the below dependencies in my microservices:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

My Logs are always coming false: [FOOMS,2e740f33c26e286d,2e740f33c26e286d,false]

My Zipkin dependencies are:

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
    <scope>runtime</scope>
</dependency>

Why am I getting false instead of true in my slueth statements? The traceId and SpanId are properly generated for all the calls though. My Zipkin is running in port 9411


Answer:

I found that I need to add a sampler percentage. By default zero percentage of the samples are sent and that is why the sleuth was not sending anything to zipkin. when I added spring.sleuth.sampler.percentage=1.0 in the properties files, it started working.

Question:

I have a Spring Boot 2.0.0 REST service where I'm trying to enable Sleuth and Zipkin to send traces to my localhost Zipkin server.

The app worked fine unti I add the two dependencies spring-cloud-starter-sleuth and spring-cloud-sleuth-zipkin to my pom.xml. Once I did that, I'm now getting a compilation error:

Project build error: Non-resolvable import POM: Could not find artifact io.zipkin.brave:brave-bom:pom:4.16.3-SNAPSHOT

I've ensured it's not a corrupt Maven package issue by deleting my .m2 folder and updating (twice).

Why am I getting this error and how can I fix it?

This is my pom.xml:

<?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>io.urig</groupId>
    <artifactId>inventory</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>inventory</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.M8</spring-cloud.version>
        <sleuth.version>2.0.0.M8</sleuth.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <!-- Sleuth automatically adds trace interceptors when in the classpath -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!-- Sends trace data to zipkin over http (defaults to http://localhost:9411/api/v2/spans) -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-sleuth</artifactId>
                <version>${sleuth.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

Answer:

This is really strange because you are using latest relase and in the GitHub spring-cloud-sleuth depends to <brave.version>4.17.2</brave.version>. And I think 4.16.3-SNAPSHOT version is not exists in the maven repo. (just checked 2.0.0.M8 depends to this version)

If you change to <sleuth.version>2.0.0.M7</sleuth.version> it does find the required dependencies.

https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/pom.xml

Question:

I am currently implementing Spring Cloud Sleuth in our project. I have a requirement to add the traceId to the response headers. Is there a way that this can be achieved?

Thanks, Anoop


Answer:

There are 2 options. One is to provide your custom extractors - http://cloud.spring.io/spring-cloud-sleuth/1.0.x/#_customizations (it will be MUCH easier with version 1.2.0). Another option (much faster) is to create your own Filter that will be registered after TraceFilter was executed and before it's closed. You can there run tracer.getCurrentSpan() and add any info you need to the response.

Question:

Looking for an example that shows integrating spring cloud sleuth with spring boot amqp (rabbit) publisher and subscriber.

I do see the following messages in the log

2016-10-21 08:35:15.708 INFO [producer,9148f56490e5742f,943ed050691842ab,false] 30928 --- [nio-8080-exec-1] a.b.c.controllers.MessagingController : Received Request to pulish with Activity OrderShipped 2016-10-21 08:35:15.730 INFO [producer,9148f56490e5742f,943ed050691842ab,false] 30928 --- [nio-8080-exec-1] a.b.c.service.ProducerService : Message published

When I look at messages on Queue, I don't see traceId or any other details added to the header. Should I use MessagePostProcessor to add these to the header?

Also what should be done on the receiving service?


Answer:

Using Spring AMQP you can set MessagePostProcessor on the RabbitTemplateusing the setBeforePublishPostProcessors method.

We implemented the org.springframework.amqp.core.MessagePostProcessor and Overrided the postProcessMessage method this way:

@Override
public org.springframework.amqp.core.Message postProcessMessage(org.springframework.amqp.core.Message message)
        throws AmqpException {
    MessagingMessageConverter converter = new MessagingMessageConverter();
    MessageBuilder<?> mb = MessageBuilder.fromMessage((Message<?>) converter.fromMessage(message));
    inject(tracer.getCurrentSpan(), mb);
    return converter.toMessage(mb.build(), message.getMessageProperties());
}

The inject method can now set all the required headers on the message, and it will be passed to the rabbitMq with the changes. You have a great example of how to implement such inject method in org.springframework.cloud.sleuth.instrument.messaging.MessagingSpanInjector

We are using v1.1.1 of spring-cloud-sleuth-stream so my example is based on this version, in next release(1.2) it will be easier.

Question:

I need to send notifications from time to time, I perform this task asynchronously. I'm using HystrixCommand as below to perform an asynchronous RestTemplate call which is not working:

@HystrixCommand
    public Future<String> notify(final Query query) {
        return new AsyncResult<String>() {
            @Override
            public String invoke() {
                String result = null;
                try {
                    ResponseEntity<HashMap> restExchange = restTemplate.exchange(url,
                            HttpMethod.POST,
                            new HttpEntity<String>(mapper.writeValueAsString(queryMap), httpHeaders),
                            HashMap.class);
                    LOGGER.info("Response code from " + url + " = " + restExchange.getStatusCodeValue());
                    result = ""+ restExchange.getStatusCodeValue();
                } catch(Exception e) {
                    LOGGER.error("Exception while sending notification! Message = " + e.getMessage(), e);
                }
                return result;
            }
        };
    }

This is what I was trying to do earlier(which didn't work either):

@HystrixCommand
    public String notify(final Query query) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    ResponseEntity<HashMap> restExchange = restTemplate.exchange(url, HttpMethod.POST,
                            new HttpEntity<String>(mapper.writeValueAsString(queryMap), httpHeaders), HashMap.class);
                    LOGGER.info("Response code from " + url + " = " + restExchange.getStatusCodeValue());

                } catch (Exception e) {
                    LOGGER.error("Exception while sending notification! Message = " + e.getMessage(), e);
                }

            }
        }).start();
    }  

P.S: Reason for adding sleuth to the tags is, performing this in a new Thread does not propagate the headers(baggage-*) so trying this hoping the Hystrix command will do the trick


Answer:

Is the method notify being called from a method in the same class? If that is the case, try calling the method notify directly from a different class where the notify method's enclosing class is injected as a dependency.

Basically, try doing this:

Instead of this: