Using Jaeger and OpenTelemetry SDKs in a mixed environment with W3C Trace-Context

Pavol Loffay
JaegerTracing
Published in
3 min readMay 26, 2020

In this article, we are going to have a look at using Jaeger clients with W3C Trace-Context propagation format. The standardized context propagation format assures interoperability between different tracing systems and instrumentation libraries. In this regard we are going to explore two use cases. First how to use OpenTelemetry SDKs in Jaeger instrumented environment. This scenario simulates interoperability between different tracing systems but also a migration path from Jaeger clients to OpenTelemetry SDK. In the second use case we are going to configure Jaeger native clients to use W3C Trace-Context.

W3C Trace-Context

Before we deep dive into the main topic let’s have a look at W3C Trace-Context. W3C Trace-Context is a standardized propagation format for trace identifiers and metadata. It contains two headers:

  • traceparent — describes the position of the incoming request in its trace graph. It encodes trace ID, parent span ID and set of flags.
  • tracestate — extends traceparent with vendor-specific data represented by a set of name/value pairs. This header is optional and can, for instance, encode tenant name.

The standardized inter-process context propagation format solves these problems:

  • exchanging trace context between different vendors
  • correlation of traces collected by different tracing vendors
  • vendor-specific metadata might be dropped by intermediaries, cloud providers and service providers if there is no standard to follow.

Now let’s have a look at OpenTelemetry Java SDK configuration in a mixed environment with Jaeger native clients.

Configure OpenTelemetry SDK with Jaeger context propagation format

In this section, we are going to have a look at the configuration of OpenTelemetry Java SDK in an environment that is instrumented with Jaeger native clients. This use case is important when we want to introduce new services instrumented with OpenTelemetry and it also showcases interoperability between different tracing instrumentations. In a mixed environment, we have to make sure that all instrumentation libraries understand the same propagation protocol.

Since existing services cannot be recompiled and redeployed to use the new context propagation format, the new services have to be configured to understand the new and old propagation formats at the same time. Follows a simple diagram showing three microservices A, B and X. Services A and B are instrumented with Jaeger and X with OpenTelemetry. Only the service X is using both propagation protocols — Jaeger and W3C Trace-Context. This ensures that “legacy” Jaeger services are able to continue the trace started by service X and vice versa.

Diagram showing service X instrumented with OpenTelemetry and services A and B instrumented with Jaeger.

Now let’s have a look at the code. We are going to configure OpenTelemetry Java SDK to use the default W3C Trace-Context and Jaeger formats simultaneously. First, let’s add OpenTelemetry maven artifacts for SDK and Jaeger context propagation format:

<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
<version>0.4.1</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-contrib-trace-propagators</artifactId>
<version>0.4.1</version>
</dependency>

and the tracer configuration:

import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.Tracer;
import io.opentelemetry.contrib.trace.propagation.JaegerPropagator; import io.opentelemetry.trace.propagation.HttpTraceContext;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation
.DefaultContextPropagators;
ContextPropagators contextPropagators = DefaultContextPropagators.builder()
.addHttpTextFormat(new JaegerPropagator())
.addHttpTextFormat(new HttpTraceContext())
.build();
OpenTelemetry.setPropagators(contextPropagators);

Tracer tracer = OpenTelemetry.getTracerProvider().get("io.example");
Span span = tracer.spanBuilder("operation").startSpan();
...

Now the tracer is configured to use both W3C Trace-Context and Jaeger propagation formats simultaneously for context injection and extraction. The legacy Jaeger instrumentations will recognize the Jaeger propagation format and drop the W3C Trace-Context.

Configure Jaeger clients with W3C Trace-Context

Jaeger native clients can be configured to use custom context propagation formats. Support for W3C Trace-Context is usually provided directly in the core artifacts. It can be configured programmatically or via an environment variable JAEGER_PROPAGATION=w3c.

The following code snippet shows the programmatic configuration that configures both Jaeger and W3C Trace-Context formats at the same time.

import io.jaegertracing.Configuration;
import io.jaegertracing.Configuration.Propagation;
Configuration configuration = Configuration.fromEnv("io.example");
configuration.getCodec()
.withPropagation(Propagation.W3C)
.withPropagation(Propagation.JAEGER);
JaegerTracer jaegerTracerWith = configuration.getTracer();

Conclusion

In this article we have shown how OpenTelemetry SDKs can be used in a heterogeneous environment with Jaeger native clients and also how W3C Trace-Context can be configured in Jaeger clients.

References

--

--

Pavol Loffay
JaegerTracing

Software engineer working in observability space. Working on Hypertrace, OpenTelemetry, Jaeger, OpenTracing, MicroProfile projects.