Distributed tracing - up1/course-springboot-2024 GitHub Wiki

Distributed tracing with Spring Boot 2

1. Add dependency in file pom.xml

  • Spring Cloud Sleuth
  • Zipkin client
<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>

2. Start Zipkin and Jaeger

Zipkin

$curl -sSL https://zipkin.io/quickstart.sh | bash -s
$java -jar zipkin.jar

Access to Zipkin server with URL=http://localhost:9411

3. Config Zipkin server in file application.properties

spring.application.name=service-1

# Zipkin
spring.zipkin.baseUrl=http://localhost:9411

4. Start services in Example Project

  • service1 (port=8081) -> service2 (port=8082)

Start service 1

$cd service1
$mvnw spring-boot:run

Start service 2

$cd service2
$mvnw spring-boot:run

Access url in each service

Distributed tracing with Spring Boot 3

Step 1 :: Add library

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
	<groupId>io.micrometer</groupId>
	<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
	<groupId>io.zipkin.reporter2</groupId>
	<artifactId>zipkin-reporter-brave</artifactId>
</dependency>

Step 2 :: Configuration

application.properties

info.app.name=My demo service
info.app.description=My demo service description
info.app.version=1.0.0

spring.application.name=demo-service
spring.output.ansi.enabled: ALWAYS

management.info.env.enabled=true
management.endpoints.web.exposure.include=health,info,prometheus


management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.tracing.sampling.probability=1.0
management.zipkin.tracing.endpoint=http://xxx:9411/api/v2/spans

logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]

application.yml

spring:
  application:
    name: demo
  output.ansi.enabled: ALWAYS

management:
  endpoints.web.exposure.include: '*'
  metrics.distribution.percentiles-histogram.http.server.requests: true
  tracing.sampling.probability: 1.0
  zipkin:
    tracing:
      endpoint: http://xxx:9411/api/v2/spans

logging.pattern.console: "%clr(%d{HH:mm:ss.SSS}){blue} %clr(%5p [${spring.application.name:}, trace_id=%X{traceId:-} span_id=%X{spanId:-}]){yellow} %clr(:){red} %clr(%m){faint}%n"

Step 3 :: Observed Aspect (AOP)

ObserveConfiguration.java

import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.aop.ObservedAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class ObserveConfiguration {
    @Bean
    ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
        return new ObservedAspect(observationRegistry);
    }
}

Step 4 :: Create Service

DemoService.java

import io.micrometer.observation.annotation.Observed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class DemoService {
    private static final Logger log = LoggerFactory.getLogger(DemoService.class);
    private final Random random = new Random();

    @Observed(name = "do.sth", contextualName = "try-do-something")
    String doSth(String userId) {
        log.info("Do something <{}>", userId);
        try {
            Thread.sleep(random.nextLong(200L)); // simulates latency
        }
        catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "TODO Next";
    }
}

Step 5 :: Create Controller

DemoTraceController.java

import io.micrometer.observation.annotation.Observed;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoTraceController {

    private final DemoService demoService;

    public DemoTraceController(DemoService demoService) {
        this.demoService = demoService;
    }

    @GetMapping("hi")
    @Observed(name = "do.sth", contextualName = "say-hi")
    public String sayHi() {
        return demoService.doSth("123");
    }

}

Call API with URL=http://localhost:8080/hi

Reference

⚠️ **GitHub.com Fallback** ⚠️