OpenTelemetry Java Agent Traceparent Extraction Boundary in Custom Middleware
0 reputation · 27 Apr 2022, 07:52 UTC
0 reputation · 27 Apr 2022, 07:52 UTC
OpenTelemetry Java instrumentation automatically extracts the W3C Tracecontext traceparent header from incoming HTTP requests and injects it into outbound calls at the server and client boundaries. When a service introduces custom middleware between the servlet container and application handlers, or when request processing moves to an async or multi-threaded executor, the automatic propagation boundary may not align with the actual execution path. The goal is to ensure downstream spans join the same trace without manually parsing headers in every custom component.
The uncertainty is where the SDK expects the propagation extension to be active. Version-specific changes in the propagation library can alter how headers are handled, and the collector configuration may need explicit propagation settings. Without the tracecontext extension enabled, spans remain isolated to the originating process, but it is unclear which configuration layer takes precedence when custom middleware intercepts the request before auto-instrumentation runs.
What is the minimal SDK or agent configuration required to make custom middleware and async handlers participate in automatic trace context propagation? Does the Java agent enforce a specific extraction point that custom middleware must not bypass, or must the propagation extension be registered separately for non-standard execution paths? Which version-specific behaviors in the propagation library should be verified before relying on automatic header handling in a multi-threaded environment?
To let custom middleware and asynchronous handlers join the same trace without manual header parsing, the Java agent only needs the default W3C TraceContext propagator to be active and the async instrumentation enabled:
OTEL_PROPAGATORS=tracecontext (or ensure the variable is not set to exclude tracecontext)OTEL_INSTRUMENTATION_COMMON_ASYNC_ENABLED=true (default in recent agent versions)No additional agent‑side registration or SDK code is required.
The OpenTelemetry Java agent installs a servlet filter (OpenTelemetryServletFilter) early in the filter chain. This filter:
traceparent header using the W3C TraceContext propagator.Context in the current thread’s ThreadLocal via Context.current().If your custom middleware is a standard javax.servlet.Filter (or Spring interceptor) that runs after the agent’s filter, it automatically receives the correct Context and any outgoing HTTP calls made within it will inherit the trace ID.
When trace context is lost, the most common causes are:
CompletableFuture without wrapping the Runnable/Callable with the current Context.OTEL_PROPAGATORS overrides the default and omits tracecontext.@Order(Ordered.HIGHEST_PRECEDENCE + 1) or set spring.boot.admin.filter.order accordingly.CompletableFuture, reactive streams), wrap the task:Context ctx = Context.current();
Runnable wrapped = Context.wrap(ctx, () -> {
// your async logic
});
executor.execute(wrapped);
OTEL_PROPAGATORS is either unset or includes tracecontext. You can check at runtime with:System.getenv("OTEL_PROPAGATORS");
OTEL_INSTRUMENTATION_COMMON_ASYNC_ENABLED is set to true; newer agents enable this by default.ContextStorage or ScopeManager replacement has been installed via system properties.tracecontext (default unless overridden).If you are unsure whether your custom middleware runs before or after the agent’s filter, please confirm the filter order (or the equivalent interceptor order) so we can tell whether a simple re‑ordering suffices or if manual context extraction is required.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.