Logo
Published on

Adding Micrometer Tracing to Spring Boot 3 Applications

Authors
  • Name
    Twitter

Guide for adding distributed logging to Spring boot 3 applications with Micrometer, Brave & Zipkin.

Required dependencies:

<!-- includes the micrometer dependency along with brave and zipkin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Application configs:

→ Spring boot 3 will generate 128-bit trace ids following the w3c format.

→ Sampling probability can be between (0.0–1.0), representing how often Micrometer will generate trace logs.

management:
tracing:
enabled:  true
sampling:
probability:  1.0

<!--  optional:  for  backwards  compatability  with  spring2  b3  -->
spring:
sleuth:
propagation:
type:  w3c,b3

Configuring Zipkin:

By default, data will be sent to Zipkin over the HTTP endpoint.

  1. To change the Zipkin server host, add the following configs:
management:
zipkin:
tracing:
endpoint:  localhost:9411
  1. To disable Zipkin altogether, annotate the @SpringBootApplication class with the following:
@EnableAutoConfiguration(exclude {ZipkinAutoConfiguration.class})
  1. If instead, you want to push the trace logs to a Kafka topic and have Zipkin consume that topic, do the following:
  • Add the Zipkin Kafka sender dependency:
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-kafka</artifactId>
</dependency>
  • Add the following class to configure the Kafka topic:
@Configuration
@EnableConfigurationProperties(KafkaProperties.class)
public  class  ZipkinConfig {
@Bean("zipkinSender")
KafkaSender  senderZipkin(KafkaProperties config, Environment environment) {
String topic = environment.getProperty("management.tracing.kafka.topic", "zipkin");
String serviceName = environment.getProperty("management.tracing.service.name", "server-name");
Map<String, Object> properties = config.buildProducerProperties();
properties.put("key.serializer", ByteArraySerializer.class.getName());
properties.put("value.serializer", ByteArraySerializer.class.getName());
properties.put(CommonClientConfigs.CLIENT_ID_CONFIG, serviceName);
properties.put("bootstrap.servers", "localhost:8888");

return  KafkaSender.newBuilder().topic(topic).overrides(properties).build();
}
}

Creating the trace payload:

We have two options when it comes to the payload, either use a predefined pattern or implement the payload on the code level.

Micrometer pattern:

→ note that the trace and span id are not included by default.

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

Code level:

@Component
@RequiredArgsConstructor
public  class  LogTracer {

private final Tracer tracer;

public  String  getTraceId() {
String traceId = "";
try {
traceId = Objects.isNull(tracer.currentSpan()) ? tracer.nextSpan().context().traceIdString():
tracer.currentSpan().context().traceIdString();
} catch (Exception error) {
//error handling
}
return traceId;
}

public  void  logData(Object data){
createPayload(data, getTraceId()) //ex: implement the payload format then push to kibana logs
}
}

References:

  1. https://github.com/micrometer-metrics/tracing/wiki/Spring-Cloud-Sleuth-3.1-Migration-Guide#high-level-overview
  2. https://openvalue.blog/posts/2022/12/16/tracing-in-spring-boot-2-and-3/
  3. https://stackoverflow.com/questions/74853681/zipkin-sender-type-and-kafka-topic-not-working-after-updating-spring-boot-3
  4. https://github.com/spring-projects/spring-boot/issues/34620