Implementing OpenTelemetry for Spring Boot Microservices

Naveen Metta
3 min readJun 4, 2024

--

credit goes to the owner : https://cloudblogs.microsoft.com/opensource/2019/05/23/announcing-opentelemetry-cncf-merged-opencensus-opentracing/
source : cloudblogs.microsoft.com/

In today’s complex microservices environments, monitoring and tracing are crucial for maintaining system health and diagnosing issues. OpenTelemetry provides a unified way to collect telemetry data from distributed systems. This guide will walk you through setting up OpenTelemetry in your Spring Boot microservices, complete with comprehensive explanations and code examples in Java.

1. Introduction to OpenTelemetry

OpenTelemetry is an open-source project aimed at providing a standardized way to collect and instrument telemetry data (traces, metrics, logs) from applications. It supports a variety of backends like Jaeger, Zipkin, and Prometheus.

2. Prerequisites

Before diving into the implementation, ensure you have the following:

  • Java Development Kit (JDK) 11 or later
  • Maven or Gradle
  • Basic understanding of Spring Boot and microservices architecture

3. Setting Up Your Spring Boot Application

First, let’s create a simple Spring Boot application. Use Spring Initializr (https://start.spring.io/) to generate a new project with the following dependencies:

  • Spring Web
  • Spring Actuator

Unzip the generated project and open it in your favorite IDE.

4. Adding OpenTelemetry Dependencies

Add the OpenTelemetry dependencies to your pom.xml file:

<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-jaeger</artifactId>
<version>1.10.0</version>
</dependency>

5. Configuring OpenTelemetry

Create a configuration class to set up OpenTelemetry. This class will initialize the OpenTelemetry SDK and configure it to export data to Jaeger.

package com.example.demo.config;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenTelemetryConfig {

@Bean
public OpenTelemetry openTelemetry() {
// Configure the Jaeger exporter
JaegerGrpcSpanExporter jaegerExporter = JaegerGrpcSpanExporter.builder()
.setEndpoint("http://localhost:14250")
.build();

// Set up the SDK tracer provider
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(jaegerExporter).build())
.build();

// Initialize the OpenTelemetry SDK
OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.build();

return openTelemetrySdk;
}
}

6. Instrumenting Your Spring Boot Application

With OpenTelemetry configured, the next step is to instrument your Spring Boot application. This involves creating spans to track various parts of your application’s execution. Here’s an example of a simple REST controller with manual span creation:

package com.example.demo.controller;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class DemoController {

private final Tracer tracer;

public DemoController(OpenTelemetry openTelemetry) {
this.tracer = openTelemetry.getTracer("com.example.demo.controller.DemoController");
}

@GetMapping("/hello")
public String hello() {
Span span = tracer.spanBuilder("hello").startSpan();
try {
// Simulate some work
Thread.sleep(1000);
return "Hello, OpenTelemetry!";
} catch (InterruptedException e) {
span.recordException(e);
throw new RuntimeException(e);
} finally {
span.end();
}
}
}

7. Running Your Application

Start your Jaeger instance using Docker:

docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 14250:14250 \
-p 9411:9411 \
jaegertracing/all-in-one:1.21

Then run your Spring Boot application:

mvn spring-boot:run

Visit http://localhost:16686 to see the traces in Jaeger.

8. Advanced Configuration

Context Propagation

Ensure context propagation across threads and network boundaries. Add the following dependencies for context propagation:

<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-annotations</artifactId>
<version>1.10.0</version>
</dependency>

Use the @WithSpan annotation to automatically create spans:

import io.opentelemetry.extension.annotations.WithSpan;
import org.springframework.stereotype.Service;

@Service
public class DemoService {

@WithSpan
public String process() {
// Simulate some work
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Processed";
}
}

9. Metrics and Logs

To collect metrics, add the following dependency:

<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-metrics-starter</artifactId>
<version>1.10.0</version>
</dependency>

And configure the metrics exporter in OpenTelemetryConfig:

import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.exporter.prometheus.PrometheusCollector;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;

@Bean
public SdkMeterProvider meterProvider() {
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().build();
PrometheusCollector.builder()
.setMeterProvider(sdkMeterProvider)
.buildAndRegister();
return sdkMeterProvider;
}

@Bean
public PrometheusHttpServer prometheusHttpServer(SdkMeterProvider meterProvider) {
return new PrometheusHttpServer(9464);
}

10. Conclusion

Integrating OpenTelemetry with Spring Boot microservices enhances your ability to monitor and troubleshoot distributed systems. By following this guide, you should have a comprehensive setup for tracing, metrics, and logging in your microservices architecture.

FAQs

Q1: What is OpenTelemetry? A: OpenTelemetry is an open-source project providing a standardized way to collect telemetry data (traces, metrics, logs) from applications.

Q2: Why use OpenTelemetry with Spring Boot? A: It provides robust observability, making it easier to monitor and troubleshoot microservices.

Q3: How do I view the telemetry data? A: Use backends like Jaeger, Zipkin, or Prometheus to visualize and analyze the collected data.

Q4: Can I use OpenTelemetry with other frameworks? A: Yes, OpenTelemetry supports various programming languages and frameworks.

--

--

Naveen Metta

I'm a Full Stack Developer with 2.5 years of experience. feel free to reach out for any help : mettanaveen701@gmail.com