It's time to dive into the practical magic of Spring Boot, Sleuth, and Zipkin so tracing becomes our best friend in microservices archaeology.
Overview of Spring Cloud Sleuth
Spring Cloud Sleuth is a library integrated into Spring Boot that adds distributed tracing to microservices, like giving your services the ability to leave footprints on every request.
It automatically adds trace identifiers (traceId) and span identifiers (spanId) to your logs. That way you can understand how your request travels through the microservice system, which services it visits, and where it gets stuck.
Like a detective analyzing fingerprints at a crime scene, Sleuth lets you pull logs and link them across different services.
Why does this matter?
- Logs without context are like random puzzle pieces. Sleuth adds a single
traceIdthat ties logs together. - You can trace request "latencies" back to the specific service.
- Convenient to use with tracing systems like Zipkin or Jaeger.
Key features of Sleuth
- Built-in identifiers
traceIdandspanId. - Integration with logging.
- Automatic timing of request execution.
- Support for HTTP, Kafka, RabbitMQ and other transports.
Setting up Sleuth in Spring Boot
Let's get practical! We'll create a simple Spring Boot microservice and integrate Sleuth.
Adding the dependency
To integrate Sleuth you need to add the dependency to your pom.xml (or build.gradle if you're using Gradle). Also we'll add Zipkin to visualize request traces.
<dependencies>
<!-- Spring Cloud Sleuth -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- Zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
Configuration
In application.yml add basic settings to enable tracing and Zipkin.
spring:
application:
name: microservice-a
sleuth:
sampler:
probability: 1.0 # 100% of requests will be traced
zipkin:
base-url: http://localhost:9411 # URL of your Zipkin server
This configuration does the following:
- Sets your service name to
microservice-a. - Sets
sampler.probability: 1.0, which means that all requests will be traced (in production it's better to lower this value). - Specifies the Zipkin server URL.
Integrating with Zipkin
Zipkin is a distributed tracing system that collects and visualizes request data. Imagine you're watching a request through a magic window: you see where it went, how long it stalled, and where it went next.
Zipkin works with traceId and spanId, which Sleuth automatically sends.
- The easiest way to run Zipkin is with Docker:
docker run -d -p 9411:9411 openzipkin/zipkin - After starting, Zipkin will be available at:
http://localhost:9411.
Demo: Tracing in microservices
Step 1. Create two microservices
Create two microservices: Service A and Service B. Service A calls Service B via REST. Our goal is to see how the request travels between them.
Main controller for Service A:
@RestController
@RequestMapping("/service-a")
public class ServiceAController {
private final RestTemplate restTemplate;
public ServiceAController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/call-service-b")
public String callServiceB() {
String response = restTemplate.getForObject("http://localhost:8081/service-b/endpoint", String.class);
return "Response from Service B: " + response;
}
}
Configuration for RestTemplate:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Service B's controller looks like this:
@RestController
@RequestMapping("/service-b")
public class ServiceBController {
@GetMapping("/endpoint")
public String endpoint() {
return "Hello from Service B!";
}
}
Step 2. Hook up Sleuth and Zipkin
Both services use the same Sleuth and Zipkin dependencies we set up earlier. Also make sure they have different names:
For Service A:
spring:
application:
name: service-a
For Service B:
spring:
application:
name: service-b
Step 3. Verify the tracing
- Start both services (on ports 8080 and 8081).
- Call Service A to initiate the request:
curl http://localhost:8080/service-a/call-service-b - Open the Zipkin UI at
http://localhost:9411.
You'll see a trace with two spans:
- First span: the controller call in Service A.
- Second span: the call from Service A to Service B.
Example logging with Sleuth
When you enable Sleuth, traceId and spanId are automatically added to logs.
Example log:
2023-10-25 12:00:00.123 INFO [service-a,traceId=1ab23cd4,spanId=2ef56gh7] Request initiated
2023-10-25 12:00:00.456 INFO [service-b,traceId=1ab23cd4,spanId=3ij89kl0] Processing request
What to watch out for
- Sampling: With
spring.sleuth.sampler.probabilityyou can configure what percentage of requests will be traced. For production it's better to use0.1(10%). - Request context: Sleuth automatically forwards trace headers like
X-B3-TraceIdbetween services. Make sure your code doesn't overwrite these headers. - Tracing errors: If Zipkin doesn't show data:
- Check the Zipkin server URL in your configuration.
- Ensure Sleuth is enabled (
spring.sleuth.enabled=true).
Real-world usage
- In production, Sleuth + Zipkin help quickly find bottlenecks. For example, if a request is slow, you can immediately see which service is at fault.
- OpenTelemetry is also a popular tool — more flexible but harder to configure.
- You can integrate tracing with logging in ELK for full observability.
By now you've not only added Sleuth and Zipkin to your projects, but you also know how to track requests like a predator hunting bugs. In the next lecture we'll dive deeper into centralized logging with ELK. Hope your microservices cross paths there again!
GO TO FULL VERSION