diff --git a/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/main/java/io/micrometer/tracing/otel/bridge/OtelTraceContext.java b/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/main/java/io/micrometer/tracing/otel/bridge/OtelTraceContext.java index 816ae520..6e018440 100644 --- a/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/main/java/io/micrometer/tracing/otel/bridge/OtelTraceContext.java +++ b/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/main/java/io/micrometer/tracing/otel/bridge/OtelTraceContext.java @@ -15,9 +15,6 @@ */ package io.micrometer.tracing.otel.bridge; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; - import io.micrometer.common.lang.Nullable; import io.micrometer.tracing.TraceContext; import io.opentelemetry.api.trace.Span; @@ -25,6 +22,9 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.trace.ReadableSpan; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + /** * OpenTelemetry implementation of a {@link TraceContext}. * @@ -116,7 +116,11 @@ public String parentId() { : this.span; if (spanContextSpanOrSpan instanceof ReadableSpan) { ReadableSpan readableSpan = (ReadableSpan) spanContextSpanOrSpan; - return readableSpan.toSpanData().getParentSpanId(); + String parentSpanId = readableSpan.toSpanData().getParentSpanId(); + if (Objects.equals(Span.getInvalid().getSpanContext().getSpanId(), parentSpanId)) { + return null; + } + return parentSpanId; } return null; } diff --git a/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/OtelTraceContextTests.java b/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/OtelTraceContextTests.java new file mode 100644 index 00000000..79084dc6 --- /dev/null +++ b/micrometer-tracing-bridges/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/OtelTraceContextTests.java @@ -0,0 +1,91 @@ +/** + * Copyright 2024 the original author or authors. + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + *
+ * https://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.micrometer.tracing.otel.bridge; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.OpenTelemetrySdkBuilder; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.BDDAssertions.then; + +class OtelTraceContextTests { + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .setSampler(io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn()) + .build(); + + OpenTelemetrySdkBuilder openTelemetrySdkBuilder = OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider); + + @Test + void should_return_null_when_parent_invalid() { + + try (OpenTelemetrySdk openTelemetrySdk = openTelemetrySdkBuilder.build()) { + Tracer otelTracer = tracer(openTelemetrySdk); + Span span = otelTracer.spanBuilder("foo").startSpan(); + + OtelTraceContext otelTraceContext = new OtelTraceContext(span); + + then(otelTraceContext.parentId()).isNull(); + } + + } + + @Test + void should_return_null_when_spans_not_sampled() { // works differently than Brave + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .setSampler(io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOff()) + .build(); + + OpenTelemetrySdkBuilder openTelemetrySdkBuilder = OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider); + + try (OpenTelemetrySdk openTelemetrySdk = openTelemetrySdkBuilder.build()) { + Tracer otelTracer = tracer(openTelemetrySdk); + Span parentSpan = otelTracer.spanBuilder("parent").startSpan(); + Span span = otelTracer.spanBuilder("foo") + .setParent(parentSpan.storeInContext(Context.current())) + .startSpan(); + + OtelTraceContext otelTraceContext = new OtelTraceContext(span); + + then(otelTraceContext.parentId()).isNull(); + } + + } + + @Test + void should_return_parentid_when_parent_valid() { + try (OpenTelemetrySdk openTelemetrySdk = openTelemetrySdkBuilder.build()) { + Tracer otelTracer = tracer(openTelemetrySdk); + Span parentSpan = otelTracer.spanBuilder("parent").startSpan(); + Span span = otelTracer.spanBuilder("foo") + .setParent(parentSpan.storeInContext(Context.current())) + .startSpan(); + + OtelTraceContext otelTraceContext = new OtelTraceContext(span); + + then(otelTraceContext.parentId()).isEqualTo(parentSpan.getSpanContext().getSpanId()); + } + + } + + private static Tracer tracer(OpenTelemetrySdk openTelemetrySdk) { + return openTelemetrySdk.getTracer("io.micrometer.micrometer-tracing"); + } + +}