From b032e900adc99457a5582715f83ee60c1c3967b4 Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Fri, 26 Jan 2024 11:09:22 -0600 Subject: [PATCH] Set incoming baggage from parent on Span Signed-off-by: Tim Quinn --- .../OpenTelemetrySpanBuilder.java | 11 ++++- .../opentelemetry/MapHeaderProvider.java | 49 +++++++++++++++++++ .../opentelemetry/TestSpanAndBaggage.java | 19 ++++++- .../opentracing/OpenTracingSpanBuilder.java | 18 ++++++- 4 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/MapHeaderProvider.java diff --git a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java index 5faff4ef285..d7da2ed3b87 100644 --- a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java +++ b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import io.helidon.tracing.Span; import io.helidon.tracing.SpanContext; +import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.context.Context; @@ -27,6 +28,7 @@ class OpenTelemetrySpanBuilder implements Span.Builder { private final SpanBuilder spanBuilder; private boolean parentSet; + private Baggage parentBaggage; OpenTelemetrySpanBuilder(SpanBuilder spanBuilder) { this.spanBuilder = spanBuilder; @@ -41,6 +43,7 @@ public Span build() { public OpenTelemetrySpanBuilder parent(SpanContext spanContext) { this.parentSet = true; spanContext.asParent(this); + parentBaggage = Baggage.fromContext(((OpenTelemetrySpanContext) spanContext).openTelemetry()); return this; } @@ -87,7 +90,11 @@ public Span start(Instant instant) { } spanBuilder.setStartTimestamp(instant); io.opentelemetry.api.trace.Span span = spanBuilder.startSpan(); - return new OpenTelemetrySpan(span); + Span result = new OpenTelemetrySpan(span); + if (parentBaggage != null) { + parentBaggage.forEach((key, baggageEntry) -> result.baggage(key, baggageEntry.getValue())); + } + return result; } // used to set open telemetry context as parent, to be equivalent in function to diff --git a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/MapHeaderProvider.java b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/MapHeaderProvider.java new file mode 100644 index 00000000000..eab43f47d13 --- /dev/null +++ b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/MapHeaderProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. + * + * 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 + * + * http://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.helidon.tracing.providers.opentelemetry; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.helidon.tracing.HeaderProvider; + +record MapHeaderProvider(Map> values) implements HeaderProvider { + + @Override + public Iterable keys() { + return values.keySet(); + } + + @Override + public Optional get(String key) { + if (!values.containsKey(key)) { + return Optional.empty(); + } + List matches = values.get(key); + return matches.isEmpty() ? Optional.empty() : Optional.of(matches.get(0)); + } + + @Override + public Iterable getAll(String key) { + return values.get(key); + } + + @Override + public boolean contains(String key) { + return values.containsKey(key); + } +} diff --git a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java index 796daa2f568..bc782f0a95f 100644 --- a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java +++ b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java @@ -15,14 +15,17 @@ */ package io.helidon.tracing.providers.opentelemetry; +import java.util.List; +import java.util.Map; import java.util.Optional; import io.helidon.common.testing.junit5.OptionalMatcher; +import io.helidon.tracing.HeaderProvider; import io.helidon.tracing.Scope; import io.helidon.tracing.Span; +import io.helidon.tracing.SpanContext; import io.helidon.tracing.Tracer; -import io.opentelemetry.context.Context; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -42,7 +45,7 @@ class TestSpanAndBaggage { @BeforeAll static void init() { originalOtelSdkAutoConfiguredSetting = System.setProperty(OTEL_AUTO_CONFIGURE_PROP, "true"); - originalOtelSdkDisabledSetting = System.setProperty(OTEL_SDK_DISABLED_PROP, "true"); + originalOtelSdkDisabledSetting = System.setProperty(OTEL_SDK_DISABLED_PROP, "false"); } @AfterAll @@ -110,4 +113,16 @@ void testActiveSpanScopeWithBaggage() { currentSpanAfterTryResourcesBlock.get().context().spanId(), containsString("00000000")); } + + @Test + void testIncomingBaggage() { + Tracer tracer = Tracer.global(); + HeaderProvider inboundHeaders = new MapHeaderProvider(Map.of("baggage", List.of("bag1=val1,bag2=val2"))); + Optional spanContextOpt = tracer.extract(inboundHeaders); + assertThat("Span context from inbound headers", spanContextOpt, OptionalMatcher.optionalPresent()); + Span span = tracer.spanBuilder("inbound").parent(spanContextOpt.get()).start(); + span.end(); + assertThat("Inbound baggage bag1", span.baggage("bag1"), OptionalMatcher.optionalValue(is("val1"))); + assertThat("Inbound baggage bag1", span.baggage("bag2"), OptionalMatcher.optionalValue(is("val2"))); + } } diff --git a/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpanBuilder.java b/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpanBuilder.java index 7e9711ad43e..16be27e0b59 100644 --- a/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpanBuilder.java +++ b/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpanBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package io.helidon.tracing.providers.opentracing; import java.time.Instant; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; import io.helidon.tracing.Span; @@ -27,6 +29,7 @@ class OpenTracingSpanBuilder implements Span.Builder { private final Tracer.SpanBuilder delegate; private final Tracer tracer; + private Map baggage; OpenTracingSpanBuilder(Tracer tracer, Tracer.SpanBuilder delegate) { this.tracer = tracer; @@ -42,6 +45,13 @@ public Span build() { public OpenTracingSpanBuilder parent(SpanContext spanContext) { if (spanContext instanceof OpenTracingContext otc) { delegate.asChildOf(otc.openTracing()); + if (baggage == null) { + baggage = new HashMap<>(); + } else { + baggage.clear(); + } + ((OpenTracingContext) spanContext).openTracing().baggageItems().forEach(entry -> baggage.put(entry.getKey(), + entry.getValue())); } return this; } @@ -83,6 +93,10 @@ public OpenTracingSpanBuilder tag(String key, Number value) { @Override public Span start(Instant instant) { long micro = TimeUnit.MILLISECONDS.toMicros(instant.toEpochMilli()); - return new OpenTracingSpan(tracer, delegate.withStartTimestamp(micro).start()); + Span result = new OpenTracingSpan(tracer, delegate.withStartTimestamp(micro).start()); + if (baggage != null) { + baggage.forEach(result::baggage); + } + return result; } }