Skip to content

Commit 3a37bbc

Browse files
committed
Fix Trace Context extraction from Lambda Context object by bypassing Muzzle Check (#1218)
*Issue #, if available:* - https://github.com/aws-observability/aws-otel-java-instrumentation/actions/runs/17954879038/job/51066448865 AWS Lambda Environment may or may not have the `getXrayTraceId` method in Lambda Context (from Lambda Core dependency). This will cause OTel's Muzzle Check to disable the AWS Lambda Instrumentation in the event that it isn't present, causing no Lambda Function Handler Span to appear Fix of previous PR: #1191 *Description of changes:* - Use `@NoMuzzle` annotation when accessing `getXrayTraceId` in Lambda Context Object, which avoids OTel's muzzle check. If `NoSuchMethodError` is caught, we do not try this logic again. - Add unit test for when `getXrayTraceId` throws `NoSuchMethodError`. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 93e29d3 commit 3a37bbc

File tree

2 files changed

+70
-10
lines changed

2 files changed

+70
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ If your change does not need a CHANGELOG entry, add the "skip changelog" label t
1616
### Enhancements
1717

1818
- Support X-Ray Trace Id extraction from Lambda Context object, and respect user-configured OTEL_PROPAGATORS in AWS Lamdba instrumentation
19-
([#1191](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1191))
19+
([#1191](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1191)) ([#1218](https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1218))

lambda-layer/patches/opentelemetry-java-instrumentation.patch

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ index a6b89d253d..e62d30eddb 100644
2525
if (!functionInstrumenter().shouldStart(parentContext, otelInput)) {
2626
return;
2727
diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/library/build.gradle.kts b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/build.gradle.kts
28-
index df605add2f..b2f01d9d4d 100644
28+
index df605add2f..e16c736990 100644
2929
--- a/instrumentation/aws-lambda/aws-lambda-core-1.0/library/build.gradle.kts
3030
+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/build.gradle.kts
31-
@@ -9,7 +9,7 @@ dependencies {
31+
@@ -5,11 +5,12 @@ plugins {
32+
dependencies {
33+
compileOnly("io.opentelemetry:opentelemetry-sdk")
34+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
35+
+ compileOnly(project(":muzzle"))
36+
3237
compileOnly("com.google.auto.value:auto-value-annotations")
3338
annotationProcessor("com.google.auto.value:auto-value")
3439

@@ -37,7 +42,7 @@ index df605add2f..b2f01d9d4d 100644
3742

3843
// We do lightweight parsing of JSON to extract HTTP headers from requests for propagation.
3944
// This will be commonly needed even for users that don't use events, but luckily it's not too big.
40-
@@ -26,6 +26,7 @@ dependencies {
45+
@@ -26,6 +27,7 @@ dependencies {
4146

4247
testImplementation(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:testing"))
4348
testImplementation("uk.org.webcompere:system-stubs-jupiter")
@@ -147,10 +152,10 @@ index 9341bf6f79..f719c1ea93 100644
147152
}
148153
diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractor.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractor.java
149154
new file mode 100644
150-
index 0000000000..e711558e05
155+
index 0000000000..6349d1bb29
151156
--- /dev/null
152157
+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractor.java
153-
@@ -0,0 +1,68 @@
158+
@@ -0,0 +1,85 @@
154159
+/*
155160
+ * Copyright The OpenTelemetry Authors
156161
+ * SPDX-License-Identifier: Apache-2.0
@@ -162,19 +167,23 @@ index 0000000000..e711558e05
162167
+
163168
+import io.opentelemetry.context.Context;
164169
+import io.opentelemetry.context.propagation.TextMapGetter;
170+
+import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
165171
+import java.util.Locale;
166172
+import java.util.Map;
173+
+import java.util.logging.Logger;
167174
+
168175
+/**
169176
+ * This class is internal and is hence not for public use. Its APIs are unstable and can change at
170177
+ * any time.
171178
+ */
172179
+public final class ParentContextExtractor {
173180
+
181+
+ private static final Logger logger = Logger.getLogger(ParentContextExtractor.class.getName());
174182
+ private static final String AWS_TRACE_HEADER_ENV_KEY = "_X_AMZN_TRACE_ID";
175183
+ private static final String AWS_TRACE_HEADER_PROP = "com.amazonaws.xray.traceHeader";
176184
+ // lower-case map getter used for extraction
177185
+ static final String AWS_TRACE_HEADER_PROPAGATOR_KEY = "x-amzn-trace-id";
186+
+ static boolean getXrayTraceIdMethodExists = true;
178187
+
179188
+ static Context extract(
180189
+ Map<String, String> headers,
@@ -188,9 +197,22 @@ index 0000000000..e711558e05
188197
+ return instrumenter.extract(mergedHeaders, MapGetter.INSTANCE);
189198
+ }
190199
+
200+
+ @NoMuzzle
191201
+ private static String getTraceHeader(
192202
+ com.amazonaws.services.lambda.runtime.Context lambdaContext) {
193-
+ String traceHeader = lambdaContext.getXrayTraceId();
203+
+ String traceHeader = null;
204+
+
205+
+ // Lambda Core dependency that is actually used by Lambda Runtime may be on an older version
206+
+ // that does not have the `getXrayTraceId` method. If `NoSuchMethodError` occurs, we do not
207+
+ // attempt invoking `getXrayTraceId` again.
208+
+ if (getXrayTraceIdMethodExists) {
209+
+ try {
210+
+ traceHeader = lambdaContext.getXrayTraceId();
211+
+ } catch (NoSuchMethodError e) {
212+
+ logger.fine("Failed to get X-Ray trace ID from lambdaContext: " + e);
213+
+ getXrayTraceIdMethodExists = false;
214+
+ }
215+
+ }
194216
+ if (traceHeader != null && !traceHeader.isEmpty()) {
195217
+ return traceHeader;
196218
+ }
@@ -234,10 +256,10 @@ index cb19d1e568..12ed174bb2 100644
234256
assertThat(spanContext.getSpanId()).isEqualTo("00f067aa0ba902b7");
235257
diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractorTest.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractorTest.java
236258
new file mode 100644
237-
index 0000000000..76fc823a65
259+
index 0000000000..4b0f354769
238260
--- /dev/null
239261
+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/library/src/test/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/internal/ParentContextExtractorTest.java
240-
@@ -0,0 +1,337 @@
262+
@@ -0,0 +1,375 @@
241263
+/*
242264
+ * Copyright The OpenTelemetry Authors
243265
+ * SPDX-License-Identifier: Apache-2.0
@@ -247,6 +269,8 @@ index 0000000000..76fc823a65
247269
+
248270
+import static org.assertj.core.api.Assertions.assertThat;
249271
+import static org.mockito.Mockito.mock;
272+
+import static org.mockito.Mockito.times;
273+
+import static org.mockito.Mockito.verify;
250274
+import static org.mockito.Mockito.when;
251275
+
252276
+import com.amazonaws.services.lambda.runtime.Context;
@@ -574,6 +598,42 @@ index 0000000000..76fc823a65
574598
+ assertThat(spanContext.getSpanId()).isEqualTo("0000000000000789");
575599
+ assertThat(spanContext.getTraceId()).isEqualTo("8a3c60f7d188f8fa79d48a391a778fa7");
576600
+ }
601+
+
602+
+ @Test
603+
+ void shouldFallbackToSystemPropertyWhenNoSuchMethodErrorThrown() {
604+
+ // given
605+
+ Map<String, String> headers = ImmutableMap.of();
606+
+ Context mockLambdaContextWithNoSuchMethodError = mock(Context.class);
607+
+ when(mockLambdaContextWithNoSuchMethodError.getXrayTraceId())
608+
+ .thenThrow(new NoSuchMethodError("getXrayTraceId method not found"));
609+
+ systemProperties.set(
610+
+ "com.amazonaws.xray.traceHeader",
611+
+ "Root=1-8a3c60f7-d188f8fa79d48a391a778fa7;Parent=0000000000000789;Sampled=1");
612+
+
613+
+ // Reset the static flag to ensure the method is attempted
614+
+ ParentContextExtractor.getXrayTraceIdMethodExists = true;
615+
+
616+
+ // when - call extract
617+
+ io.opentelemetry.context.Context context =
618+
+ ParentContextExtractor.extract(
619+
+ headers, INSTRUMENTER_WITH_B3_XRAY_PROPAGATORS, mockLambdaContextWithNoSuchMethodError);
620+
+
621+
+ // then
622+
+ Span span = Span.fromContext(context);
623+
+ SpanContext spanContext = span.getSpanContext();
624+
+ assertThat(spanContext.isValid()).isTrue();
625+
+ assertThat(spanContext.getSpanId()).isEqualTo("0000000000000789");
626+
+ assertThat(spanContext.getTraceId()).isEqualTo("8a3c60f7d188f8fa79d48a391a778fa7");
627+
+ // Verify getXrayTraceId was called only once
628+
+ assertThat(ParentContextExtractor.getXrayTraceIdMethodExists).isFalse();
629+
+ verify(mockLambdaContextWithNoSuchMethodError, times(1)).getXrayTraceId();
630+
+
631+
+ // when - call extract again
632+
+ ParentContextExtractor.extract(
633+
+ headers, INSTRUMENTER_WITH_B3_XRAY_PROPAGATORS, mockLambdaContextWithNoSuchMethodError);
634+
+ // Verify the call count of getXrayTraceId is still 1
635+
+ verify(mockLambdaContextWithNoSuchMethodError, times(1)).getXrayTraceId();
636+
+ }
577637
+}
578638
diff --git a/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaRequestHandlerInstrumentation.java b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaRequestHandlerInstrumentation.java
579639
index e059250807..1fa80c3735 100644
@@ -614,7 +674,7 @@ index 4cd11fc0c4..7b7d62755c 100644
614674
}
615675

616676
diff --git a/version.gradle.kts b/version.gradle.kts
617-
index 7900c9a4d9..80383d7c22 100644
677+
index ec9690086c..b267166804 100644
618678
--- a/version.gradle.kts
619679
+++ b/version.gradle.kts
620680
@@ -1,5 +1,5 @@

0 commit comments

Comments
 (0)