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.
In this article
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:
Spring Cloud Sleuth defines Spring Boot auto-configuration for distributed tracing. It automatically configures:
Here are a few unique capabilities of Spring Cloud Sleuth:
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.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:
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:
mvn clean verify
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.
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:
docker-compose up
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: