Spring Cloud Zipkin + Sleuth - Distributed tracing system
Hello everyone, today, we will create four different simple microservices (account, product, cart, order) that interact with each other on different ports, then we will Implement distributed tracing using Sleuth and Zipkin.
Open a new browser window and hit the URL http://localhost:9411/zipkin
What is Sleuth?
Sleuth is used to generate and attach the trace id, and span id to the logs so that these can then be used by tools like Zipkin and ELK for storage and analysis. For more information: Click here
What is Zipkin?
Zipkin is an open-source distributed system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data. Zipkin provides the UI interface to analyze the traces and call graph details between services. For more information: Click here
Step 1: Create Account Service
Project Directory
Spring Boot Dependency Management
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0</version> <relativePath /> </parent> <groupId>com.knf.dev.demo</groupId> <artifactId>account</artifactId> <version>0.0.1-SNAPSHOT</version> <name>account</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.0-RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories></project>
Rest Controller and Main Driver
package com.knf.dev.demo.account;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;
@SpringBootApplicationpublic class AccountServiceApplication { private static final Logger LOG = LoggerFactory. getLogger(AccountServiceApplication.class);
@Bean public RestTemplate restTemplate() { return new RestTemplate(); }
public static void main(String[] args) { SpringApplication.run(AccountServiceApplication.class, args); }
@RestController public class AccountController { @Autowired RestTemplate restTemplate;
@GetMapping(value = "/account") public String account() { LOG.info("Inside account service"); String responseFromProductService = restTemplate. getForObject("http://localhost:9090/product", String.class); LOG.info("Successfully communicated " + "with product service"); return responseFromProductService; } }}
application.yml
Add application name and server port,
spring: application: name: accountserver: port: 9091
Step 2: Create Product Service
Project Directory
Spring Boot Dependency Management
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0</version> <relativePath /> </parent> <groupId>com.knf.dev.demo</groupId> <artifactId>product</artifactId> <version>0.0.1-SNAPSHOT</version> <name>product</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.0-RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories></project>
Rest Controller and Main Driver
package com.knf.dev.demo.product;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;
@SpringBootApplicationpublic class ProductServiceApplication { private static final Logger LOG = LoggerFactory. getLogger(ProductServiceApplication.class);
@Bean public RestTemplate restTemplate() { return new RestTemplate(); }
public static void main(String[] args) { SpringApplication.run(ProductServiceApplication.class, args); }
@RestController public class ProductController { @Autowired RestTemplate restTemplate;
@GetMapping(value = "/product") public String product() { LOG.info("Inside product service"); String responseFromCartService = restTemplate. getForObject("http://localhost:9092/cart", String.class); LOG.info("Successfully communicated " + "with cart service"); return "Greetings from product" + ">>" + responseFromCartService; } }}
application.yml
Add application name and server port,
spring: application: name: productserver: port: 9090
Step 3: Create Cart Service
Project Directory
Spring Boot Dependency Management
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.knf.dev.demo</groupId> <artifactId>cart</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cart</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.0-RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories></project>
Rest Controller and Main Driver
package com.knf.dev.demo.cart;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;
@SpringBootApplicationpublic class CartServiceApplication { private static final Logger LOG = LoggerFactory. getLogger(CartServiceApplication.class);
@Bean public RestTemplate restTemplate() { return new RestTemplate(); }
public static void main(String[] args) { SpringApplication.run(CartServiceApplication.class, args); }
@RestController public class CartController { @Autowired RestTemplate restTemplate;
@GetMapping(value = "/cart") public String cart() { LOG.info("Inside cart service"); String responseFromOrderService = restTemplate. getForObject("http://localhost:9093/order", String.class); LOG.info("Successfully communicated " + "with order service"); return "Greetings from cart" + ">>" + responseFromOrderService; } }}
application.yml
Add application name and server port,
spring: application: name: cartserver: port: 9092
Step 4: Create Order Service
Project Directory
Spring Boot Dependency Management
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.knf.dev.demo</groupId> <artifactId>order</artifactId> <version>0.0.1-SNAPSHOT</version> <name>order</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.0-RC1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories></project>
Rest Controller and Main Driver
package com.knf.dev.demo.order;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;
@SpringBootApplicationpublic class OrderServiceApplication { private static final Logger LOG = LoggerFactory. getLogger(OrderServiceApplication.class);
public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); }
@RestController public class OrderController {
@GetMapping(value = "/order") public String order() { LOG.info("Inside order service"); return "Greetings from order"; } }}
application.yml
Add application name and server port,
spring: application: name: orderserver: port: 9093
Step 5: Install Zipkin
Download the latest release as a self-contained executable jar.
curl -sSL https://zipkin.io/quickstart.sh | bash -sjava -jar zipkin.jar
or
The Docker Zipkin project is able to build docker images, provide scripts and a docker-compose.yml for launching pre-built images. The quickest start is to run the latest image directly:
docker run -d -p 9411:9411 openzipkin/zipkin
Step 6: Run Zipkin
java -jar zipkin.jar
Step 7: Start all the 4 applications
Do a final maven build using command mvn clean install in microservices, start all the 4 applications,
Step 8: Verify
Hit this URL in your local system, http://localhost:9091/account
Click on Find Trace. You will see details of four running microservices.
Click on the SHOW button.
Click on the Dependencies button.
Finally, copy the trace Id from the Zipkin dashboard and look into the respective log files to see the log messages.