From a96e6f35df228e1d6ff24624fa9a8ba8829a127b Mon Sep 17 00:00:00 2001 From: Prashant Srivastava Date: Mon, 13 Jan 2025 21:02:28 -0800 Subject: [PATCH 1/3] add application signals attributes to unsampled spans --- ...AwsApplicationSignalsCustomizerProvider.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java index c1ffc13884..b841d8a169 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java @@ -207,8 +207,25 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder( // If running on Lambda, we just need to export 100% spans and skip generating any Application // Signals metrics. if (isLambdaEnvironment()) { + String tracesEndpoint = + Optional.ofNullable(System.getenv(AWS_XRAY_DAEMON_ADDRESS_CONFIG)) + .orElse(DEFAULT_UDP_ENDPOINT); + SpanExporter spanExporter = + new OtlpUdpSpanExporterBuilder() + .setPayloadSampleDecision(TracePayloadSampleDecision.UNSAMPLED) + .setEndpoint(tracesEndpoint) + .build(); + + // Wrap the udp exporter with the AwsMetricsAttributesSpanExporter to add Application + // Signals attributes to unsampled spans too + SpanExporter appSignalsSpanExporter = + AwsMetricAttributesSpanExporterBuilder.create( + spanExporter, ResourceHolder.getResource()) + .build(); + tracerProviderBuilder.addSpanProcessor( AwsUnsampledOnlySpanProcessorBuilder.create() + .setSpanExporter(appSignalsSpanExporter) .setMaxExportBatchSize(LAMBDA_SPAN_EXPORT_BATCH_SIZE) .build()); return tracerProviderBuilder; From 2a0ac5afbed51819a337fe70c640e121366f8c64 Mon Sep 17 00:00:00 2001 From: Prashant Srivastava Date: Mon, 13 Jan 2025 21:03:37 -0800 Subject: [PATCH 2/3] add otel patch to fix duplicate root lambda spans --- .../opentelemetry-java-instrumentation.patch | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/lambda-layer/patches/opentelemetry-java-instrumentation.patch b/lambda-layer/patches/opentelemetry-java-instrumentation.patch index 1bc36876d2..73aebdca1e 100644 --- a/lambda-layer/patches/opentelemetry-java-instrumentation.patch +++ b/lambda-layer/patches/opentelemetry-java-instrumentation.patch @@ -642,4 +642,90 @@ index cc1414c0bf..db8a59b046 100644 +val alphaVersion = "1.33.6-adot-lambda1-alpha" allprojects { - if (findProperty("otel.stable") != "true") { \ No newline at end of file + if (findProperty("otel.stable") != "true") { +diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestHandlerInstrumentation.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestHandlerInstrumentation.java +index 2332f24a8f..0743cdea75 100644 +--- a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestHandlerInstrumentation.java ++++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestHandlerInstrumentation.java +@@ -10,7 +10,9 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers. + import static io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0.AwsLambdaInstrumentationHelper.functionInstrumenter; + import static net.bytebuddy.matcher.ElementMatchers.isMethod; + import static net.bytebuddy.matcher.ElementMatchers.isPublic; ++import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; + import static net.bytebuddy.matcher.ElementMatchers.named; ++import static net.bytebuddy.matcher.ElementMatchers.not; + import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + + import com.amazonaws.services.lambda.runtime.Context; +@@ -35,7 +37,8 @@ public class AwsLambdaRequestHandlerInstrumentation implements TypeInstrumentati + + @Override + public ElementMatcher typeMatcher() { +- return implementsInterface(named("com.amazonaws.services.lambda.runtime.RequestHandler")); ++ return implementsInterface(named("com.amazonaws.services.lambda.runtime.RequestHandler")) ++ .and(not(nameStartsWith("com.amazonaws.services.lambda.runtime.api.client"))); + } + + @Override +diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaTest.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaTest.java +index af939fcb6d..8b8398950a 100644 +--- a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaTest.java ++++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaTest.java +@@ -5,14 +5,19 @@ + + package io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0; + ++import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; + import static org.assertj.core.api.Assertions.assertThat; + + import com.amazonaws.services.lambda.runtime.Context; + import com.amazonaws.services.lambda.runtime.RequestHandler; ++import com.amazonaws.services.lambda.runtime.api.client.AwsLambdaInternalRequestHandler; ++import io.opentelemetry.api.trace.SpanKind; + import io.opentelemetry.instrumentation.awslambdacore.v1_0.AbstractAwsLambdaTest; + import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; + import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; ++import io.opentelemetry.semconv.SemanticAttributes; + import org.junit.jupiter.api.AfterEach; ++import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.extension.RegisterExtension; + + public class AwsLambdaTest extends AbstractAwsLambdaTest { +@@ -35,6 +40,22 @@ public class AwsLambdaTest extends AbstractAwsLambdaTest { + assertThat(testing.forceFlushCalled()).isTrue(); + } + ++ @Test ++ void awsLambdaInternalHandlerIgnoredAndUserHandlerTraced() { ++ RequestHandler handler = new AwsLambdaInternalRequestHandler(handler()); ++ String result = handler.handleRequest("hello", context()); ++ assertThat(result).isEqualTo("world"); ++ testing() ++ .waitAndAssertTraces( ++ trace -> ++ trace.hasSpansSatisfyingExactly( ++ span -> ++ span.hasName("my_function") ++ .hasKind(SpanKind.SERVER) ++ .hasAttributesSatisfyingExactly( ++ equalTo(SemanticAttributes.FAAS_INVOCATION_ID, "1-22-333")))); ++ } ++ + private static final class TestRequestHandler implements RequestHandler { + + @Override +diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/AbstractAwsLambdaTest.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/AbstractAwsLambdaTest.java +index 94a85244e2..25a32896aa 100644 +--- a/instrumentation/aws-lambda/aws-lambda-core-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/AbstractAwsLambdaTest.java ++++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/testing/src/main/java/io/opentelemetry/instrumentation/awslambdacore/v1_0/AbstractAwsLambdaTest.java +@@ -53,6 +53,10 @@ public abstract class AbstractAwsLambdaTest { + assertThat(testing().forceFlushCalled()).isTrue(); + } + ++ protected Context context() { ++ return context; ++ } ++ + @Test + void handlerTraced() { + String result = handler().handleRequest("hello", context); From 6b789d6a462162fdfff095e5943823d30fbdb947 Mon Sep 17 00:00:00 2001 From: Prashant Srivastava Date: Tue, 14 Jan 2025 14:57:30 -0800 Subject: [PATCH 3/3] skip unsampled udp exporter if otlp endpoint is configured --- .../providers/AwsApplicationSignalsCustomizerProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java index b841d8a169..58dc0afee6 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java @@ -206,7 +206,8 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder( // If running on Lambda, we just need to export 100% spans and skip generating any Application // Signals metrics. - if (isLambdaEnvironment()) { + if (isLambdaEnvironment() + && System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG) == null) { String tracesEndpoint = Optional.ofNullable(System.getenv(AWS_XRAY_DAEMON_ADDRESS_CONFIG)) .orElse(DEFAULT_UDP_ENDPOINT);