Distributed tracing - up1/course-springboot-2024 GitHub Wiki
- 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>
Zipkin
$curl -sSL https://zipkin.io/quickstart.sh | bash -s
$java -jar zipkin.jar
Access to Zipkin server with URL=http://localhost:9411
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
- Service 1 = http://localhost:8081/service1/call
- Service 2 = http://localhost:8082/service2/call
- Code Example
<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>
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"
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);
}
}
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";
}
}
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