I'd like to create and activate a Span with a given Trace ID value instead of an autogenerated one.
Context: I am using OpenTelemetry bridge. Trace ID is sent using custom header (not traceparent). I still want the traceparent header to work like it does but in case it is empty I am trying to start a span using Trace ID provided from another (legacy) header.
Example that I tried so far (not sure if it is even remotely a correct approach) - new Span is indeed started but the Trace ID value is still the autogenerated one.
var traceId = legacyTraceIdHeaderValue.replaceAll("-", "");
LOG.info("legacy traceId: {}", traceId);
var contextWithCustomTraceId = tracer.traceContextBuilder()
.traceId(traceId)
.sampled(true)
.build();
var span = this.tracer.spanBuilder().setParent(contextWithCustomTraceId);
try (Tracer.SpanInScope ws = tracer.withSpan(span.start())) {
// wrapped code here, in my case it was this as I am implementing Spring Servlet Filter: chain.doFilter(req, res);
LOG.info("Span started");
} finally {
span.end();
}
EDIT: After looking at micrometer-tracing code I think what I should do is:
- Implement a custom TextMapPropagator that will delegate to
W3CTraceContextPropagator
in casetraceparent
header is present or do customised context extraction in case another header is used. - Register this implementation as a conditional Bean with custom property value (see
OpenTelemetryAutoConfiguration
):
@Bean
@ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "my-custom-w3c-extension")
- Enable this in Spring Application Properties
management.tracing.propagation.type="my-custom-w3c-extension"
Alternatively the custom propagator might be a totally separate implementation (not using W3CTraceContextPropagator
as delegate) and they can be coupled together in Bean definition by using TextMapPropagator.composite
- that way both should run but there might be no guarantee on the order.