Dash0 acquires Polar Signals

Last updated:

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:
java
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:

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

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

bash
mvn clean verify

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

text
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:

text
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:

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

This would show a log entry like below:

text
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.

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

This would show a log entry like below:

text
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:

text
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:

text
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:

text
docker-compose up

OpenTelemetry-Native Observability with Dash0

Dash0 is built on OpenTelemetry. Any application instrumented with an OpenTelemetry SDK, and any OpenTelemetry Collector, can send traces, metrics, and logs to Dash0 over OTLP. In Dash0 you can:

  • Explore traces in a waterfall, a flame graph, or a graph of how a request flowed across services.
  • Find what slow or failing requests have in common: Triage compares erroneous or slow spans with a baseline and highlights the attribute values that differ.
  • Move between signals: The span sidebar shows the related logs and events for each span.

Because your telemetry stays in OpenTelemetry format, you can point the exporter at another backend without re-instrumenting.

Start a free trial of Dash0.

Authors
Erez Berkner
Erez Berkner