From 42fa0f706239e737ae811f72fc9411bf464f6c7c Mon Sep 17 00:00:00 2001 From: liustve Date: Fri, 24 Jan 2025 19:32:48 +0000 Subject: [PATCH 1/6] added support for Lineage in Xray Trace Header --- .../awsxray/propagator/AwsXrayPropagator.java | 126 +++++++++++------ .../AwsXrayCompositePropagatorTest.java | 78 +++++++++++ .../propagator/AwsXrayPropagatorTest.java | 131 ++++++++++-------- 3 files changed, 239 insertions(+), 96 deletions(-) create mode 100644 aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayCompositePropagatorTest.java diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index 2d8de301a..be9aef7e5 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -5,9 +5,10 @@ package io.opentelemetry.contrib.awsxray.propagator; +import static io.opentelemetry.api.internal.OtelEncodingUtils.isValidBase16String; + import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.baggage.BaggageBuilder; -import io.opentelemetry.api.baggage.BaggageEntry; import io.opentelemetry.api.internal.StringUtils; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; @@ -21,7 +22,7 @@ import io.opentelemetry.context.propagation.TextMapSetter; import java.util.Collections; import java.util.List; -import java.util.function.BiConsumer; +import java.util.Set; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -68,6 +69,15 @@ public final class AwsXrayPropagator implements TextMapPropagator { private static final char IS_SAMPLED = '1'; private static final char NOT_SAMPLED = '0'; + private static final String LINEAGE_KEY = "Lineage"; + private static final char LINEAGE_DELIMITER = ':'; + private static final int LINEAGE_MAX_LENGTH = 18; + private static final int LINEAGE_MIN_LENGTH = 12; + private static final int LINEAGE_HASH_LENGTH = 8; + private static final int LINEAGE_MAX_LOOP_COUNTER = 32767; + private static final int LINEAGE_MAX_REQUEST_COUNTER = 255; + private static final int LINEAGE_MIN_COUNTER = 0; + private static final List FIELDS = Collections.singletonList(TRACE_HEADER_KEY); private static final AwsXrayPropagator INSTANCE = new AwsXrayPropagator(); @@ -127,34 +137,19 @@ public void inject(Context context, @Nullable C carrier, TextMapSetter se .append(samplingFlag); Baggage baggage = Baggage.fromContext(context); - // Truncate baggage to 256 chars per X-Ray spec. - baggage.forEach( - new BiConsumer() { - - private int baggageWrittenBytes; - - @Override - public void accept(String key, BaggageEntry entry) { - if (key.equals(TRACE_ID_KEY) - || key.equals(PARENT_ID_KEY) - || key.equals(SAMPLED_FLAG_KEY)) { - return; - } - // Size is key/value pair, excludes delimiter. - int size = key.length() + entry.getValue().length() + 1; - if (baggageWrittenBytes + size > 256) { - return; - } - traceHeader - .append(TRACE_HEADER_DELIMITER) - .append(key) - .append(KV_DELIMITER) - .append(entry.getValue()); - baggageWrittenBytes += size; - } - }); - - setter.set(carrier, TRACE_HEADER_KEY, traceHeader.toString()); + String lineageV2Header = baggage.getEntryValue(LINEAGE_KEY); + + if (lineageV2Header != null) { + traceHeader + .append(TRACE_HEADER_DELIMITER) + .append(LINEAGE_KEY) + .append(KV_DELIMITER) + .append(lineageV2Header); + } + + // add 256 character truncation + String truncatedTraceHeader = traceHeader.substring(0, Math.min(traceHeader.length(), 256)); + setter.set(carrier, TRACE_HEADER_KEY, truncatedTraceHeader); } @Override @@ -183,10 +178,20 @@ private static Context getContextFromHeader( String traceId = TraceId.getInvalid(); String spanId = SpanId.getInvalid(); + String lineageV2Header; Boolean isSampled = false; - BaggageBuilder baggage = null; - int baggageReadBytes = 0; + Baggage contextBaggage = Baggage.fromContext(context); + BaggageBuilder baggageBuilder = Baggage.builder(); + Set baggageMap = contextBaggage.asMap().keySet(); + + // Copying baggage over to new Baggage object to add Lineage key + for (String baggageKey : baggageMap) { + String baggageValue = contextBaggage.getEntryValue(baggageKey); + if (baggageValue != null) { + baggageBuilder.put(baggageKey, baggageValue); + } + } int pos = 0; while (pos < traceHeader.length()) { @@ -215,12 +220,11 @@ private static Context getContextFromHeader( spanId = parseSpanId(value); } else if (trimmedPart.startsWith(SAMPLED_FLAG_KEY)) { isSampled = parseTraceFlag(value); - } else if (baggageReadBytes + trimmedPart.length() <= 256) { - if (baggage == null) { - baggage = Baggage.builder(); + } else if (trimmedPart.startsWith(LINEAGE_KEY)) { + lineageV2Header = parseLineageV2Header(value); + if (isValidLineage(lineageV2Header)) { + baggageBuilder.put(LINEAGE_KEY, lineageV2Header); } - baggage.put(trimmedPart.substring(0, equalsIndex), value); - baggageReadBytes += trimmedPart.length(); } } if (isSampled == null) { @@ -243,12 +247,17 @@ private static Context getContextFromHeader( spanId, isSampled ? TraceFlags.getSampled() : TraceFlags.getDefault(), TraceState.getDefault()); + if (spanContext.isValid()) { context = context.with(Span.wrap(spanContext)); } - if (baggage != null) { - context = context.with(baggage.build()); + + Baggage baggage = baggageBuilder.build(); + + if (!baggage.isEmpty()) { + context = context.with(baggage); } + return context; } @@ -316,6 +325,37 @@ private static String parseSpanId(String xrayParentId) { return xrayParentId; } + private static String parseLineageV2Header(String xrayLineageHeader) { + long numOfDelimiters = xrayLineageHeader.chars().filter(ch -> ch == LINEAGE_DELIMITER).count(); + + if (xrayLineageHeader.length() < LINEAGE_MIN_LENGTH + || xrayLineageHeader.length() > LINEAGE_MAX_LENGTH + || numOfDelimiters != 2) { + return AwsXrayPropagator.getInvalidLineageV2Header(); + } + + return xrayLineageHeader; + } + + private static boolean isValidLineage(String key) { + String[] split = key.split(":"); + String hash = split[1]; + int loopCounter = parseIntOrReturnNegative(split[0]); + int requestCounter = parseIntOrReturnNegative(split[2]); + + boolean isHashValid = hash.length() == LINEAGE_HASH_LENGTH && isValidBase16String(hash); + boolean isValidRequestCounter = + requestCounter <= LINEAGE_MAX_REQUEST_COUNTER && requestCounter >= LINEAGE_MIN_COUNTER; + boolean isValidLoopCounter = + loopCounter <= LINEAGE_MAX_LOOP_COUNTER && loopCounter >= LINEAGE_MIN_COUNTER; + + return isHashValid && isValidRequestCounter && isValidLoopCounter; + } + + private static String getInvalidLineageV2Header() { + return "-1:11111111:0"; + } + @Nullable private static Boolean parseTraceFlag(String xraySampledFlag) { if (xraySampledFlag.length() != SAMPLED_FLAG_LENGTH) { @@ -332,4 +372,12 @@ private static Boolean parseTraceFlag(String xraySampledFlag) { return null; } } + + private static int parseIntOrReturnNegative(String num) { + try { + return Integer.parseInt(num); + } catch (NumberFormatException e) { + return -1; + } + } } diff --git a/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayCompositePropagatorTest.java b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayCompositePropagatorTest.java new file mode 100644 index 000000000..53e806fdc --- /dev/null +++ b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayCompositePropagatorTest.java @@ -0,0 +1,78 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.awsxray.propagator; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapPropagator; +import java.util.LinkedHashMap; +import org.junit.jupiter.api.Test; + +public class AwsXrayCompositePropagatorTest extends AwsXrayPropagatorTest { + + @Override + TextMapPropagator propagator() { + return TextMapPropagator.composite( + W3CBaggagePropagator.getInstance(), + AwsXrayPropagator.getInstance(), + W3CTraceContextPropagator.getInstance()); + } + + @Test + void extract_traceContextOverridesXray() { + LinkedHashMap carrier = new LinkedHashMap<>(); + String w3cTraceContextTraceId = "4bf92f3577b34da6a3ce929d0e0e4736"; + String w3cTraceContextSpanId = "00f067aa0ba902b7"; + String traceParent = + String.format("00-%s-%s-01", w3cTraceContextTraceId, w3cTraceContextSpanId); + String traceState = "rojo=00f067aa0ba902b7"; + String xrayTrace = String.format("Root=1-%s;Parent=%s;Sampled=0", TRACE_ID, SPAN_ID); + + carrier.put("traceparent", traceParent); + carrier.put("tracestate", traceState); + carrier.put("X-Amzn-Trace-Id", xrayTrace); + + SpanContext actualContext = getSpanContext(subject.extract(Context.current(), carrier, GETTER)); + + assertThat(actualContext.getTraceId()).isEqualTo(w3cTraceContextTraceId); + assertThat(actualContext.getSpanId()).isEqualTo(w3cTraceContextSpanId); + assertThat(actualContext.isSampled()).isEqualTo(true); + } + + @Test + void extract_xrayOverridesTraceContext() { + TextMapPropagator propagator = + TextMapPropagator.composite( + W3CBaggagePropagator.getInstance(), + W3CTraceContextPropagator.getInstance(), + AwsXrayPropagator.getInstance()); + + LinkedHashMap carrier = new LinkedHashMap<>(); + String w3cTraceContextTraceId = "4bf92f3577b34da6a3ce929d0e0e4736"; + String w3cTraceContextSpanId = "00f067aa0ba902b7"; + String traceParent = + String.format("00-%s-%s-01", w3cTraceContextTraceId, w3cTraceContextSpanId); + String traceState = "rojo=00f067aa0ba902b7"; + String xrayTrace = + String.format( + "Root=1-%s;Parent=%s;Sampled=0", "8a3c60f7-d188f8fa79d48a391a778fa6", SPAN_ID); + + carrier.put("traceparent", traceParent); + carrier.put("tracestate", traceState); + carrier.put("X-Amzn-Trace-Id", xrayTrace); + + SpanContext actualContext = + getSpanContext(propagator.extract(Context.current(), carrier, GETTER)); + + assertThat(actualContext.getTraceId()).isEqualTo(TRACE_ID); + assertThat(actualContext.getSpanId()).isEqualTo(SPAN_ID); + assertThat(actualContext.isSampled()).isEqualTo(false); + } +} diff --git a/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java index e9cc564ac..3230e225f 100644 --- a/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java +++ b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java @@ -21,10 +21,12 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class AwsXrayPropagatorTest { @@ -54,7 +56,7 @@ TextMapPropagator propagator() { @Test void fields_valid() { - assertThat(subject.fields()).containsOnly("X-Amzn-Trace-Id"); + assertThat(subject.fields()).contains("X-Amzn-Trace-Id"); } @Test @@ -97,53 +99,33 @@ void inject_WithBaggage() { SpanContext.create( TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()), Context.current()) - .with( - Baggage.builder() - .put("cat", "meow") - .put("dog", "bark") - .put("Root", "ignored") - .put("Parent", "ignored") - .put("Sampled", "ignored") - .build()), + .with(Baggage.builder().put("cat", "ignored").put("dog", "ignored").build()), carrier, SETTER); + // all non-lineage baggage is dropped from trace header assertThat(carrier) .containsEntry( TRACE_HEADER_KEY, - "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;" - + "cat=meow;dog=bark"); + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0"); } @Test - void inject_WithBaggage_LimitTruncates() { + void inject_WithLineage() { Map carrier = new LinkedHashMap<>(); - // Limit is 256 characters for all baggage. We add a 254-character key/value pair and a - // 3 character key value pair. - String key1 = Stream.generate(() -> "a").limit(252).collect(Collectors.joining()); - String value1 = "a"; // 252 + 1 (=) + 1 = 254 - - String key2 = "b"; - String value2 = "b"; // 1 + 1 (=) + 1 = 3 - - Baggage baggage = Baggage.builder().put(key1, value1).put(key2, value2).build(); - subject.inject( withSpanContext( SpanContext.create( TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()), Context.current()) - .with(baggage), + .with(Baggage.builder().put("Lineage", "32767:e65a2c4d:255").build()), carrier, SETTER); assertThat(carrier) .containsEntry( TRACE_HEADER_KEY, - "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;" - + key1 - + '=' - + value1); + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255"); } @Test @@ -233,49 +215,57 @@ void extract_DifferentPartOrder() { } @Test - void extract_AdditionalFields() { + void extract_WithLineage() { Map carrier = new LinkedHashMap<>(); carrier.put( TRACE_HEADER_KEY, - "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Foo=Bar"); + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=32767:e65a2c4d:255"); Context context = subject.extract(Context.current(), carrier, GETTER); assertThat(getSpanContext(context)) .isEqualTo( SpanContext.createFromRemoteParent( TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault())); - assertThat(Baggage.fromContext(context).getEntryValue("Foo")).isEqualTo("Bar"); + assertThat(Baggage.fromContext(context).getEntryValue("Lineage")) + .isEqualTo("32767:e65a2c4d:255"); } @Test - void extract_Baggage_LimitTruncates() { - // Limit is 256 characters for all baggage. We add a 254-character key/value pair and a - // 3 character key value pair. - String key1 = Stream.generate(() -> "a").limit(252).collect(Collectors.joining()); - String value1 = "a"; // 252 + 1 (=) + 1 = 254 + void extract_inject_ValidTraceHeader() { + Map carrier1 = new LinkedHashMap<>(); + carrier1.put( + TRACE_HEADER_KEY, + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=32767:e65a2c4d:255"); - String key2 = "b"; - String value2 = "b"; // 1 + 1 (=) + 1 = 3 + Context context = subject.extract(Context.current(), carrier1, GETTER); - Map carrier = new LinkedHashMap<>(); - carrier.put( + // inject extracted trace context into new trace header + Map carrier2 = new LinkedHashMap<>(); + subject.inject(context, carrier2, SETTER); + + assertThat(carrier2) + .containsEntry( + TRACE_HEADER_KEY, + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=32767:e65a2c4d:255"); + } + + @Test + void extract_inject_InvalidLineage() { + Map carrier1 = new LinkedHashMap<>(); + carrier1.put( TRACE_HEADER_KEY, - "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;" - + key1 - + '=' - + value1 - + ';' - + key2 - + '=' - + value2); + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=1:badc0de:13"); - Context context = subject.extract(Context.current(), carrier, GETTER); - assertThat(getSpanContext(context)) - .isEqualTo( - SpanContext.createFromRemoteParent( - TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault())); - assertThat(Baggage.fromContext(context).getEntryValue(key1)).isEqualTo(value1); - assertThat(Baggage.fromContext(context).getEntryValue(key2)).isNull(); + Context context = subject.extract(Context.current(), carrier1, GETTER); + + // inject extracted trace context into new trace header + Map carrier2 = new LinkedHashMap<>(); + subject.inject(context, carrier2, SETTER); + + assertThat(carrier2) + .containsEntry( + TRACE_HEADER_KEY, + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1"); } @Test @@ -381,6 +371,33 @@ private void verifyInvalidBehavior(Map invalidHeaders) { assertThat(getSpanContext(result)).isSameAs(SpanContext.getInvalid()); } + @ParameterizedTest + @MethodSource("providesBadLineages") + void extract_invalidLineage(String lineage) { + Map carrier = new LinkedHashMap<>(); + carrier.put( + TRACE_HEADER_KEY, + String.format( + "Root=2-1a2a3a4a-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=%s", + lineage)); + Context context = subject.extract(Context.current(), carrier, GETTER); + assertThat(Baggage.fromContext(context).getEntryValue("Lineage")).isNull(); + } + + static Stream providesBadLineages() { + return Stream.of( + Arguments.of("1::"), + Arguments.of("1"), + Arguments.of(""), + Arguments.of(":"), + Arguments.of("::"), + Arguments.of("1:badc0de:13"), + Arguments.of(":fbadc0de:13"), + Arguments.of("1:fbadc0de:"), + Arguments.of("1::1"), + Arguments.of("65535:fbadc0de:255")); + } + @Test void extract_nullContext() { assertThat(subject.extract(null, Collections.emptyMap(), GETTER)).isSameAs(Context.root()); @@ -485,11 +502,11 @@ void extract_InvalidTraceId_WrongVersion() { .isSameAs(SpanContext.getInvalid()); } - static Context withSpanContext(SpanContext spanContext, Context context) { + private static Context withSpanContext(SpanContext spanContext, Context context) { return context.with(Span.wrap(spanContext)); } - static SpanContext getSpanContext(Context context) { + SpanContext getSpanContext(Context context) { return Span.fromContext(context).getSpanContext(); } } From b49754b415509c02193324e751497140f4a0149f Mon Sep 17 00:00:00 2001 From: liustve Date: Tue, 28 Jan 2025 20:02:58 +0000 Subject: [PATCH 2/6] cleaned up code and added additional test case --- .../awsxray/propagator/AwsXrayPropagator.java | 9 ++---- .../propagator/AwsXrayPropagatorTest.java | 30 ++++++++++++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index be9aef7e5..8d24d0dc4 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -77,6 +77,7 @@ public final class AwsXrayPropagator implements TextMapPropagator { private static final int LINEAGE_MAX_LOOP_COUNTER = 32767; private static final int LINEAGE_MAX_REQUEST_COUNTER = 255; private static final int LINEAGE_MIN_COUNTER = 0; + private static final String INVALID_LINEAGE = "-1:11111111:0"; private static final List FIELDS = Collections.singletonList(TRACE_HEADER_KEY); @@ -331,14 +332,14 @@ private static String parseLineageV2Header(String xrayLineageHeader) { if (xrayLineageHeader.length() < LINEAGE_MIN_LENGTH || xrayLineageHeader.length() > LINEAGE_MAX_LENGTH || numOfDelimiters != 2) { - return AwsXrayPropagator.getInvalidLineageV2Header(); + return INVALID_LINEAGE; } return xrayLineageHeader; } private static boolean isValidLineage(String key) { - String[] split = key.split(":"); + String[] split = key.split(String.valueOf(LINEAGE_DELIMITER)); String hash = split[1]; int loopCounter = parseIntOrReturnNegative(split[0]); int requestCounter = parseIntOrReturnNegative(split[2]); @@ -352,10 +353,6 @@ private static boolean isValidLineage(String key) { return isHashValid && isValidRequestCounter && isValidLoopCounter; } - private static String getInvalidLineageV2Header() { - return "-1:11111111:0"; - } - @Nullable private static Boolean parseTraceFlag(String xraySampledFlag) { if (xraySampledFlag.length() != SAMPLED_FLAG_LENGTH) { diff --git a/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java index 3230e225f..0e10046a5 100644 --- a/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java +++ b/aws-xray-propagator/src/test/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagatorTest.java @@ -230,6 +230,32 @@ void extract_WithLineage() { .isEqualTo("32767:e65a2c4d:255"); } + @Test + void extract_AddedLineagePreservesExistingBaggage() { + Baggage expectedBaggage = + Baggage.builder() + .put("cat", "meow") + .put("dog", "bark") + .put("Lineage", "32767:e65a2c4d:255") + .build(); + Map carrier = new LinkedHashMap<>(); + carrier.put( + TRACE_HEADER_KEY, + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1;Lineage=32767:e65a2c4d:255"); + + Context context = + subject.extract( + Context.current().with(Baggage.builder().put("cat", "meow").put("dog", "bark").build()), + carrier, + GETTER); + assertThat(getSpanContext(context)) + .isEqualTo( + SpanContext.createFromRemoteParent( + TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault())); + + assertThat(Baggage.fromContext(context).asMap()).isEqualTo(expectedBaggage.asMap()); + } + @Test void extract_inject_ValidTraceHeader() { Map carrier1 = new LinkedHashMap<>(); @@ -395,7 +421,9 @@ static Stream providesBadLineages() { Arguments.of(":fbadc0de:13"), Arguments.of("1:fbadc0de:"), Arguments.of("1::1"), - Arguments.of("65535:fbadc0de:255")); + Arguments.of("65535:fbadc0de:255"), + Arguments.of("-213:e65a2c4d:255"), + Arguments.of("213:e65a2c4d:-22")); } @Test From 16ad65b3bb0e41927f563a8ebc04d61954a565f8 Mon Sep 17 00:00:00 2001 From: liustve Date: Tue, 28 Jan 2025 20:31:34 +0000 Subject: [PATCH 3/6] removed v2 from lineage names --- .../awsxray/propagator/AwsXrayPropagator.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index 8d24d0dc4..c714ad17e 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -138,14 +138,14 @@ public void inject(Context context, @Nullable C carrier, TextMapSetter se .append(samplingFlag); Baggage baggage = Baggage.fromContext(context); - String lineageV2Header = baggage.getEntryValue(LINEAGE_KEY); + String lineageHeader = baggage.getEntryValue(LINEAGE_KEY); - if (lineageV2Header != null) { + if (lineageHeader != null) { traceHeader .append(TRACE_HEADER_DELIMITER) .append(LINEAGE_KEY) .append(KV_DELIMITER) - .append(lineageV2Header); + .append(lineageHeader); } // add 256 character truncation @@ -179,7 +179,7 @@ private static Context getContextFromHeader( String traceId = TraceId.getInvalid(); String spanId = SpanId.getInvalid(); - String lineageV2Header; + String lineageHeader; Boolean isSampled = false; Baggage contextBaggage = Baggage.fromContext(context); @@ -222,9 +222,9 @@ private static Context getContextFromHeader( } else if (trimmedPart.startsWith(SAMPLED_FLAG_KEY)) { isSampled = parseTraceFlag(value); } else if (trimmedPart.startsWith(LINEAGE_KEY)) { - lineageV2Header = parseLineageV2Header(value); - if (isValidLineage(lineageV2Header)) { - baggageBuilder.put(LINEAGE_KEY, lineageV2Header); + lineageHeader = parseLineageHeader(value); + if (isValidLineage(lineageHeader)) { + baggageBuilder.put(LINEAGE_KEY, lineageHeader); } } } @@ -326,7 +326,7 @@ private static String parseSpanId(String xrayParentId) { return xrayParentId; } - private static String parseLineageV2Header(String xrayLineageHeader) { + private static String parseLineageHeader(String xrayLineageHeader) { long numOfDelimiters = xrayLineageHeader.chars().filter(ch -> ch == LINEAGE_DELIMITER).count(); if (xrayLineageHeader.length() < LINEAGE_MIN_LENGTH From 6b4517f1ec7be5267ef7b6252420154d2111a7e1 Mon Sep 17 00:00:00 2001 From: liustve Date: Mon, 3 Feb 2025 18:35:00 +0000 Subject: [PATCH 4/6] changed variable names --- .../awsxray/propagator/AwsXrayPropagator.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index c714ad17e..9414dacb6 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -74,8 +74,8 @@ public final class AwsXrayPropagator implements TextMapPropagator { private static final int LINEAGE_MAX_LENGTH = 18; private static final int LINEAGE_MIN_LENGTH = 12; private static final int LINEAGE_HASH_LENGTH = 8; - private static final int LINEAGE_MAX_LOOP_COUNTER = 32767; - private static final int LINEAGE_MAX_REQUEST_COUNTER = 255; + private static final int LINEAGE_MAX_COUNTER1 = 32767; + private static final int LINEAGE_MAX_COUNTER2 = 255; private static final int LINEAGE_MIN_COUNTER = 0; private static final String INVALID_LINEAGE = "-1:11111111:0"; @@ -341,16 +341,16 @@ private static String parseLineageHeader(String xrayLineageHeader) { private static boolean isValidLineage(String key) { String[] split = key.split(String.valueOf(LINEAGE_DELIMITER)); String hash = split[1]; - int loopCounter = parseIntOrReturnNegative(split[0]); - int requestCounter = parseIntOrReturnNegative(split[2]); + int counter1 = parseIntOrReturnNegative(split[0]); + int counter2 = parseIntOrReturnNegative(split[2]); boolean isHashValid = hash.length() == LINEAGE_HASH_LENGTH && isValidBase16String(hash); - boolean isValidRequestCounter = - requestCounter <= LINEAGE_MAX_REQUEST_COUNTER && requestCounter >= LINEAGE_MIN_COUNTER; - boolean isValidLoopCounter = - loopCounter <= LINEAGE_MAX_LOOP_COUNTER && loopCounter >= LINEAGE_MIN_COUNTER; + boolean isValidCounter2 = + counter2 <= LINEAGE_MAX_COUNTER2 && counter2 >= LINEAGE_MIN_COUNTER; + boolean isValidCounter1 = + counter1 <= LINEAGE_MAX_COUNTER1 && counter1 >= LINEAGE_MIN_COUNTER; - return isHashValid && isValidRequestCounter && isValidLoopCounter; + return isHashValid && isValidCounter2 && isValidCounter1; } @Nullable From efbb27fc83dd9dd1ef546e54ac543d0e55d039a0 Mon Sep 17 00:00:00 2001 From: liustve Date: Mon, 3 Feb 2025 18:38:28 +0000 Subject: [PATCH 5/6] formatting fix --- .../contrib/awsxray/propagator/AwsXrayPropagator.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index 9414dacb6..8d09337e0 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -345,10 +345,8 @@ private static boolean isValidLineage(String key) { int counter2 = parseIntOrReturnNegative(split[2]); boolean isHashValid = hash.length() == LINEAGE_HASH_LENGTH && isValidBase16String(hash); - boolean isValidCounter2 = - counter2 <= LINEAGE_MAX_COUNTER2 && counter2 >= LINEAGE_MIN_COUNTER; - boolean isValidCounter1 = - counter1 <= LINEAGE_MAX_COUNTER1 && counter1 >= LINEAGE_MIN_COUNTER; + boolean isValidCounter2 = counter2 <= LINEAGE_MAX_COUNTER2 && counter2 >= LINEAGE_MIN_COUNTER; + boolean isValidCounter1 = counter1 <= LINEAGE_MAX_COUNTER1 && counter1 >= LINEAGE_MIN_COUNTER; return isHashValid && isValidCounter2 && isValidCounter1; } From 3a6090fc640c3a678b8d82e083c065636e217d85 Mon Sep 17 00:00:00 2001 From: liustve Date: Sat, 15 Feb 2025 00:02:22 +0000 Subject: [PATCH 6/6] more cleanup --- .../contrib/awsxray/propagator/AwsXrayPropagator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java index 8d09337e0..721d01443 100644 --- a/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java +++ b/aws-xray-propagator/src/main/java/io/opentelemetry/contrib/awsxray/propagator/AwsXrayPropagator.java @@ -78,6 +78,7 @@ public final class AwsXrayPropagator implements TextMapPropagator { private static final int LINEAGE_MAX_COUNTER2 = 255; private static final int LINEAGE_MIN_COUNTER = 0; private static final String INVALID_LINEAGE = "-1:11111111:0"; + private static final int NUM_OF_LINEAGE_DELIMITERS = 2; private static final List FIELDS = Collections.singletonList(TRACE_HEADER_KEY); @@ -225,6 +226,8 @@ private static Context getContextFromHeader( lineageHeader = parseLineageHeader(value); if (isValidLineage(lineageHeader)) { baggageBuilder.put(LINEAGE_KEY, lineageHeader); + } else { + logger.fine("Invalid Lineage header: " + value); } } } @@ -331,7 +334,7 @@ private static String parseLineageHeader(String xrayLineageHeader) { if (xrayLineageHeader.length() < LINEAGE_MIN_LENGTH || xrayLineageHeader.length() > LINEAGE_MAX_LENGTH - || numOfDelimiters != 2) { + || numOfDelimiters != NUM_OF_LINEAGE_DELIMITERS) { return INVALID_LINEAGE; }