Core Java

Observability Beyond Logs: Distributed Tracing with OpenTelemetry in Java

In the age of microservices and cloud-native systems, debugging with logs alone is like navigating a maze with a flashlight—you only see a piece of the puzzle. Distributed tracing offers a complete map.

In this article, you’ll learn how to integrate OpenTelemetry tracing into a Java (Spring Boot) application, send traces to Jaeger or Grafana Tempo, and dramatically improve your observability and debugging capabilities.

The Problem: Logs Don’t Tell the Whole Story

Logs are useful, but:

  • They’re often siloed per service.
  • Correlating log lines across services is painful.
  • Latency issues and errors may not surface clearly.

As systems get more distributed, observability must evolve. Enter OpenTelemetry.

What is OpenTelemetry?

OpenTelemetry (OTel) is a vendor-neutral standard for collecting telemetry data—traces, metrics, and logs—from your applications.

In this article, we’ll focus on distributed tracing, which allows you to:

  • See how a single request flows through services.
  • Understand bottlenecks via latency visualization.
  • Automatically correlate logs, traces, and metrics.

Step 1: Add OpenTelemetry to Your Spring Boot Project

Dependencies

Use OpenTelemetry Java agent for auto-instrumentation, or manually add dependencies for full control.

Here’s a manual example using opentelemetry-sdk and opentelemetry-exporter-otlp:

<!-- pom.xml -->
<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-api</artifactId>
  <version>1.34.0</version>
</dependency>
<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-sdk</artifactId>
  <version>1.34.0</version>
</dependency>
<dependency>
  <groupId>io.opentelemetry</groupId>
  <artifactId>opentelemetry-exporter-otlp</artifactId>
  <version>1.34.0</version>
</dependency>

Step 2: Configure OpenTelemetry in Your Application

Initialize OpenTelemetry with OTLP (OpenTelemetry Protocol) exporter:

public class TracingConfig {

    public static OpenTelemetry initOpenTelemetry() {
        OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
            .setEndpoint("http://localhost:4317")
            .build();

        SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
            .addSpanProcessor(SimpleSpanProcessor.create(spanExporter))
            .setResource(Resource.getDefault()
                .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "my-java-service"))))
            .build();

        OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder()
            .setTracerProvider(tracerProvider)
            .build();

        return openTelemetry;
    }
}

Call initOpenTelemetry() at application startup.

Tip: Use environment variables or config files in production, not hardcoded endpoints.

Step 3: Add Tracing to Your Code

Grab a tracer and create spans manually:

OpenTelemetry openTelemetry = TracingConfig.initOpenTelemetry();
Tracer tracer = openTelemetry.getTracer("my-app");

@GetMapping("/hello")
public String hello() {
    Span span = tracer.spanBuilder("handleHelloRequest").startSpan();
    try (Scope scope = span.makeCurrent()) {
        // business logic here
        return "Hello, tracing!";
    } finally {
        span.end();
    }
}

Or let Spring auto-instrument it using OpenTelemetry instrumentation libraries.

Step 4: Export Traces to Jaeger or Tempo

Option 1: Jaeger

Spin up Jaeger locally:

docker run -d --name jaeger \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 16686:16686 \
  -p 4317:4317 \
  jaegertracing/all-in-one:latest
  • Visit http://localhost:16686 to view traces.
  • Set endpoint to http://localhost:4317 in your exporter.

Option 2: Grafana Tempo

Tempo works well with Grafana dashboards and Loki logs.

Spin it up using Docker Compose:

tempo:
  image: grafana/tempo:latest
  ports:
    - "4317:4317"   # OTLP gRPC

Use Grafana to visualize traces alongside logs and metrics.

Step 5: Correlate Spans Across Services

OpenTelemetry automatically injects context headers (like traceparent) into HTTP requests.

In a multi-service setup:

  • Client Service starts a span and sends HTTP request.
  • Server Service extracts trace context and continues the trace.

Enable context propagation like so:

TextMapPropagator propagator = W3CTraceContextPropagator.getInstance();
Context context = propagator.extract(Context.current(), headers, MapGetter.INSTANCE);
Span span = tracer.spanBuilder("downstreamCall").setParent(context).startSpan();

Frameworks like Spring Cloud Sleuth (deprecated in favor of Micrometer Tracing) or OpenTelemetry’s Java Agent can do this automatically.

Step 6: Analyze and Debug with Traces

Once your application is emitting traces:

  • Open Jaeger or Grafana
  • Search by service name or trace ID
  • Click into a trace to:
    • View duration and breakdown
    • Spot bottlenecks
    • Trace errors through stack

🔗 You can even correlate trace IDs in logs by injecting them using MDC or structured logging.

Real-World Use Case: Debugging a Slow API

Imagine a client calls /checkout, which calls:

  • /inventory/pricing/email

With tracing:

  • You see the end-to-end latency in Jaeger.
  • Notice /pricing adds 2 seconds delay.
  • Drill into the span to view tags and logs.

You just saved hours of log spelunking.

Clean Up and Best Practices

  • Name spans meaningfully ("loadUser", "saveToDatabase")
  • Use attributes (tags) to enrich spans:
span.setAttribute("user.id", userId);
span.setAttribute("operation", "checkout");
  • Don’t trace everything. Use sampling for high-throughput services.
  • Avoid sensitive data in spans (e.g., passwords, PII).

Final Thoughts

Distributed tracing isn’t just a nice-to-have—it’s a game-changer for cloud-native observability. With OpenTelemetry, you get a standardized, vendor-neutral way to:

  • Understand request flows
  • Pinpoint performance issues
  • Reduce mean-time-to-resolution (MTTR)

And when integrated with tools like Jaeger or Grafana Tempo, your traces become a powerful storytelling tool about what your app is really doing.

Resources

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button