[[howto]]
= "`How-to`" Guides

include::_attributes.adoc[]

This section provides answers to some common "`how do I do that...?`" questions that often arise when using {project-full-name}.
Its coverage is not exhaustive, but it does cover quite a lot.

If you have a specific problem that we do not cover here, you might want to check out
https://stackoverflow.com/tags/{project-name}[stackoverflow.com] to see if someone has already provided an answer.
Stack Overflow is also a great place to ask new questions (please use the `{project-name}` tag).

We are also more than happy to extend this section.
If you want to add a "`how-to`", send us a {github-code}[pull request].

[[how-to-set-up-sleuth-with-brave]]
== How to Set Up Sleuth with Brave?

Add the Sleuth starter to the classpath.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
    <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${release.train-version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
          </dependencies>
    </dependencyManagement>

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

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
}
----
====

[[how-to-set-up-sleuth-with-brave-zipkin-http]]
== How to Set Up Sleuth with Brave & Zipkin via HTTP?

Add the Sleuth starter and Zipkin to the classpath.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
    <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${release.train-version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
          </dependencies>
    </dependencyManagement>

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

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
    implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
}
----
====

[[how-to-set-up-sleuth-with-brave-zipkin-messaging]]
== How to Set Up Sleuth with Brave & Zipkin via Messaging?

If you want to use RabbitMQ, Kafka or ActiveMQ instead of HTTP, add the `spring-rabbit`, `spring-kafka` or `org.apache.activemq:activemq-client` dependency.
The default destination name is `Zipkin`.

If using Kafka, you must add the Kafka dependency.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
    <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${release.train-version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
          </dependencies>
    </dependencyManagement>

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

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
    implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
    implementation "org.springframework.kafka:spring-kafka"
}
----
====

Also, you need to set the property `spring.zipkin.sender.type` property accordingly:

[source,yaml]
----
spring.zipkin.sender.type: kafka
----

If you want Sleuth over RabbitMQ, add the `spring-cloud-starter-sleuth`, `spring-cloud-sleuth-zipkin` and `spring-rabbit` dependencies.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
    <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${release.train-version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
          </dependencies>
    </dependencyManagement>

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

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
    implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
    implementation "org.springframework.amqp:spring-rabbit"
}
----
====

If you want Sleuth over ActiveMQ, add the `spring-cloud-starter-sleuth`, `spring-cloud-sleuth-zipkin` and `activemq-client` dependencies.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
    <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-dependencies</artifactId>
                  <version>${release.train-version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
          </dependencies>
    </dependencyManagement>

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

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
    implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
    implementation "org.apache.activemq:activemq-client"
}
----
====

Also, you need to set the property `spring.zipkin.sender.type` property accordingly:

[source,yaml]
----
spring.zipkin.sender.type: activemq
----

[[how-to-see-spans-in-an-external-system]]
== How to See Spans in an External System?

If you can't see spans get reported to an external system (e.g. Zipkin), then it's most likely due to the following causes:

* <<not-sampled-span,Your span is not being sampled>>
* <<missing-dependency,You have forgotten to add the dependency to report to an external system (e.g. `spring-cloud-sleuth-zipkin`)>>
* <<connection-misconfiguration,You have misconfigured the connection to the external system>>

[[not-sampled-span]]
=== Your Span Is Not Being Sampled

In order to check if the span is not being sampled it's enough to see if the exportable flag is being set.
Let's look at the following example:

[indent=0]
----
2020-10-21 12:01:16.285  INFO [backend,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] Example              : Hello world!
----

If the boolean value in the section `[backend,0b6aaf642574edd3,0b6aaf642574edd3,true]` is `true` means that the span is being sampled and should be reported.

[[missing-dependency]]
=== Missing Dependency

Up till Sleuth 3.0.0 the dependency `spring-cloud-starter-zipkin` included the `spring-cloud-starter-sleuth` dependency and the `spring-cloud-sleuth-zipkin` dependency.
With 3.0.0 `spring-cloud-starter-zipkin` was removed, so you need to change it to `spring-cloud-sleuth-zipkin`.

[[connection-misconfiguration]]
=== Connection Misconfiguration

Double check if the remote system address is correct (e.g. `spring.zipkin.baseUrl`) and that if trying to communicate over the broker, your broker connection is set up properly.

[[how-to-make-components-work]]
== How to Make RestTemplate, WebClient, etc. Work?

If you're observing that the tracing context is not being propagated then cause is one of the following:

* We are not instrumenting the given library
* We are instrumenting the library, however you misconfigured the setup

In case of lack of instrumentation capabilities please file https://github.com/spring-cloud/spring-cloud-sleuth/issues[an issue] with a request to add such instrumentation.

In case of the misconfiguration please ensure that the client you're using to communicate is a Spring bean.
If you create the client manually via the `new` operator the instrumentation will not work.

Example where instrumentation will work:

====
[source,java,indent=0]
----
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration(proxyBeanMethods = false)
class MyConfiguration {
    @Bean RestTemplate myRestTemplate() {
        return new RestTemplate();
    }
}

@Service
class MyService {
	private final RestTemplate restTemplate;

	MyService(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}

	String makeACall() {
		return this.restTemplate.getForObject("http://example.com", String.class);
	}

}

----
====

Example where instrumentation will **NOT** work:

====
[source,java,indent=0]
----
@Service
class MyService {

	String makeACall() {
		// This will not work because RestTemplate is not a bean
		return new RestTemplate().getForObject("http://example.com", String.class);
	}

}

----
====

[[how-to-add-headers-to-the-http-server-response]]
== How to Add Headers to the HTTP Server Response?

Register a filter that will set the server response.

====
[source,java,indent=0]
----
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;

import javax.servlet.Filter;
import org.springframework.web.server.WebFilter;

@Configuration(proxyBeanMethods = false)
class MyConfig {

		// Example of a servlet Filter for non-reactive applications
		@Bean
		Filter traceIdInResponseFilter(Tracer tracer) {
			return (request, response, chain) -> {
				Span currentSpan = tracer.currentSpan();
				if (currentSpan != null) {
					HttpServletResponse resp = (HttpServletResponse) response;
					// putting trace id value in [mytraceid] response header
					resp.addHeader("mytraceid", currentSpan.context().traceId());
				}
				chain.doFilter(request, response);
			};
		}

		// Example of a reactive WebFilter for reactive applications
		@Bean
		WebFilter traceIdInResponseFilter(Tracer tracer) {
			return (exchange, chain) -> {
				Span currentSpan = tracer.currentSpan();
				if (currentSpan != null) {
					// putting trace id value in [mytraceid] response header
					exchange.getResponse().getHeaders().add("mytraceid", currentSpan.context().traceId());
				}
				return chain.filter(exchange);
			};
		}
}

----
====

IMPORTANT: Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin.

[[how-to-cutomize-http-client-spans]]
== How to Customize HTTP Client Spans?

Register a bean of `HttpRequestParser` type whose name is `HttpClientRequestParser.NAME` to add customization for the request side.
Register a bean of `HttpResponseParser` type whose name is `HttpClientRequestParser.NAME` to add customization for the response side.

====
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/integration/parser/WebClientCustomParserTests.java[tags=client_parser_config,indent=0]
----
====

[[how-to-cutomize-http-server-spans]]
== How to Customize HTTP Server Spans?

Register a bean of `HttpRequestParser` type whose name is `HttpServerRequestParser.NAME` to add customization for the request side.
Register a bean of `HttpResponseParser` type whose name is `HttpServerResponseParser.NAME` to add customization for the response side.

====
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerParserTests.java[tags=server_parser_config,indent=0]
----
====

IMPORTANT: Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin.

[[how-to-see-application-name-in-logs]]
== How to See the Application Name in Logs?

Assuming that you haven't changed the default logging format set the `spring.application.name` property in `bootstrap.yml`, not in `application.yml`.

TIP: With the new Spring Cloud configuration bootstrap this should no longer be required since there will be no Bootstrap Context anymore.

[[how-to-change-context-propagation]]
== How to Change The Context Propagation Mechanism?

To use the provided defaults you can set the `spring.sleuth.propagation.type` property.
The value can be a list in which case you will propagate more tracing headers.

For Brave we support `AWS`, `B3`, `W3C` propagation types.

If you want to provide a custom propagation mechanism set the `spring.sleuth.propagation.type` property to `CUSTOM` and implement your own bean (`Propagation.Factory` for Brave).
Below you can find the examples:

====
[source,java,indent=0,subs="verbatim,attributes"]
----
@Component
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/BravePropagationTests.java[tags=custom_propagator,indent=0]
----
====

[[how-to-implement-own-tracer]]
== How to Implement My Own Tracer?

Spring Cloud Sleuth API contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave implementation.
You can check how both tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge` module.
