• Guide Content

Zipkin with Spring Boot: Distributed Tracing for Spring Apps

What Are Spring Boot and Spring Cloud Sleuth? 

The Spring Framework provides a programming and configuration model based on Java, which lets you build applications that can be deployed on any platform.

The Spring Boot project provides framework modules that let you quickly create applications and run them as standalone deployment units. It automatically configures Spring and third-party libraries during the build process. It also helps you build common patterns in distributed systems, such as service discovery, circuit breakers, micro-proxies, and distributed sessions. 

Spring Boot contains a component called Spring Cloud Sleuth, which provides Spring Boot auto-configuration for distributed tracing. Combined with the open source Zipkin library, it allows you to perform distributed tracing for Spring applications.

This is part of a series of articles about Zipkin.

Spring Cloud Sleuth and Zipkin 

Spring Cloud Sleuth, combined with Zipkin, allows you to perform distributed tracing for Spring applications.

Zipkin is a distributed tracking system originally developed by Twitter and now available as open source. Zipkin visualizes trace data between and within services. Its Java-enabled architecture consists of four components: 

  • Collector—validates received data and passes it to the storage service.
  • Storage service—you can define any common database such as Cassandra, ElasticSearch, or MySQL.
  • Search service—supports flexible queries on distributed trace data.
  • Web UI—lets you visualize data and perform searches.

Spring Cloud Sleuth defines Spring Boot auto-configuration for distributed tracing. It automatically configures:

  • Spans—defines how to break down trace data.
  • Samples—defines how many traces to store.
  • Remote fields—defines whether “baggage” should be sent to provide additional context about a trace.
  • Libraries—defines which libraries should be traced.

Here are a few unique capabilities of Spring Cloud Sleuth:

  • Adds Trace ID and Scope ID to Simple Logging Facade for Java with Mapped Diagnostic Context (SLF4J MDC). This lets you get all the logs from a specific trace or scope in the log collector.
  • Measures common input and output points in Spring applications, including servlet filters, scheduled actions, REST templates, feign clients, and message channels.
  • If spring-cloud-sleuth-zipkin is available, Spring Cloud Sleuth generates and reports Zipkin-compatible traces via HTTP, sending them to a Zipkin collector service on port 9411 by default.

Example: Distributed Tracing with Spring Cloud Sleuth and Zipkin 

Create a Spring Application

This tutorial uses Spring Web and Spring Cloud Sleuth for distributed tracing of a Spring application.

Set up a Spring application that uses Spring Web and Spring Cloud Sleuth:

  1. Add Spring Web and Spring Cloud Sleuth while creating an application.
  2. Use the following code to create a controller with two request mappings:

public class DemoController {

  private static final demoLogger logger = demoLoggerFactory.getLogger(demoController.class);

  private RestTemplate demoRestTemplate;

  @Value("${spring.application.name}")
  private String demoApplication;

  public demoController(RestTemplate demoRestTemplate) {
    this.demoRestTemplate = demoRestTemplate;
  }

@GetMapping("/demoPath1")
public ResponseEntity demoPath1() {
  logger.info("Request at {} for request /demoPath1 ", applicationName);
  String requestResponse = demoRestTemplate.getForObject("http://localhost:8090/service/demoPath2”, String.class);
  return ResponseEntity.ok("response from /demoPath1 + "+ response);
}

@GetMapping("/path2")
public ResponseEntity demoPath2(){
  logger.info("Request at {} at /demoPath2", applicationName);
  return ResponseEntity.ok("response from /demoPath2 ");

Here, demoPath1 calls demoPath2 at a fixed port (8090). Two separate instances of the same application are running here.

Use the following code to inject RestTemplate as a bean and allow Spring Cloud Sleuth to add headers with trace id and span id in the outgoing request:

@Bean
  public RestTemplate demoRestTemplate(RestTemplateBuilder builder) {
    return builder.build();
  }

Run the following command in the terminal to build the application:

Run the following command to start one instance of the application:

java -jar \
target/Distributed-Service-0.0.1-SNAPSHOT.jar \
--spring.application.name=first-service-instance \
--server.port=8080

In a separate terminal, run the following command to run the second instance:

java -jar \
target/Distributed-Service-0.0.1-SNAPSHOT.jar \
--spring.application.name=first-service-instance \
--server.port=8080

Once both instances are running, use the following commands in separate terminals to call them:

curl -i http://localhost:8080/service/demoPath1

This would show a log entry like below:

INFO [first-service-instance,222f3b00a283c75c,222f3b00a283c75c] 41114 --- [nio-8080-exec-1] c.a.p.distributedservice.Controller      : Incoming request at first-service-instance for request /demoPath1

The square brackets after INFO contain the instance name, trace id, and span id, respectively. They are the same for the first incoming request since there is no trace id.

curl -i http://localhost:8090/service/demoPath2

This would show a log entry like below:

INFO [Service-2,222f3b00a283c75c,13194db963293a22] 41052 --- [nio-8090-exec-1] c.a.p.distributedservice.Controller      : Incoming request at second-service-instance at /demoPath2

The span id has changed here, but the trace id remains the same.

Visualize a Trace With Zipkin

This tutorial uses Zipkin to visualize the traces.

To integrate Zipkin into the application:

Add the following to application dependencies:

INFO [Service-2,222f3b00a283c75c,13194db963293a22] 41052 --- [nio-8090-exec-1] c.a.p.distributedservice.Controller      : Incoming request at second-service-instance at /demoPath2

Create a docker-compose file to start the Zipkin server:

version: '3.1'
services:
  zipkin:
    image: openzipkin/zipkin:2
    ports:
      - '9411:9411'

In a separate terminal window, use the following command to start the server:

Distributed Tracing with Lumigo

Lumigo is a cloud native observability tool, purpose-built to navigate the complexities of microservices. Through automated distributed tracing, Lumigo stitches together the many components of a containerized application and tracks every service in a request. When an error or failure occurs, users will see not only the impacted service, but the entire request in one visual map so you can easily understand the root cause, limit impact and prevent future failures.

With deep debugging data in to applications and infrastructure, developers have all the information they need to monitor and troubleshoot their containers with out any of the manual work:

  • Automatic correlation of logs, metrics and traces into end-to-end visualization of requests and full system map of applications
  • Monitor and debug third party APIs and managed services (ex. Amazon DynamoDB, Twilio, Stripe)
  • Go from alert (in Slack, PagerDuty and other workflow tools) to root cause analysis in one click
  • Understand system behavior and explore performance and cost issues

Get a free Lumigo account!