From 4fe7ce4ff18e63df1fbad058d63b9a581f166b53 Mon Sep 17 00:00:00 2001 From: Luke Zhang Date: Tue, 8 Jul 2025 15:45:03 -0700 Subject: [PATCH] [Lambda Java v2.11.x] Merge All Code Changes from v1.33.x Branch into v2.11.x This change merges all private Lambda Java updates from the v1.33 branch into the v2.11.x branch. I performed a 'git rebase v2.11' on the v1.33 branch, reviewed all changes, and completed the build and testing process. The resulting Lambda layer generated trace data identical to the version built directly from the v2.11.x branch (excluding this PR). Here is the list of all migrated PRs: Build layer during CI/CD workflows + some minor refactoring #989 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/989 support java11 runtime for lambda #1001 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1001 Unique artifact names for upload and merge for download #1014 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1014 Bug fixes] Lambda - duplicate lambda spans + appsignals from unsampled spans #1000 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1000 Fix: Lambda Topology Issue (#1016) https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1016 Fix: Lambda Topology Issue (#1016) #1085 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1085 feat: Support microservice span in Lambda Java environment. #1053 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1053 Test Tested Java11, 17, and 21 Lambda functions. Manually tested PR-1000 and PR-1053. Both work as expected in the v2.11 branch. MicroService (SpringBoot) support works well. I verified attribute Trace.lambda.multiple server can be found in the Lambda server span, once we have Servlet instrumentation enabled with OTEL_INSTRUMENTATION_SERVLET_ENABLED. Note: The changes in the patch files are not included in this PR. They should have been reviewed and incorporated as part of this migration: Upgrade Java Lambda Layer to 2.x #1076 https://github.com/aws-observability/aws-otel-java-instrumentation/pull/1076 --- .github/workflows/main-build.yml | 2 +- .github/workflows/release-lambda.yml | 8 +- ...sApplicationSignalsCustomizerProvider.java | 24 ++- .../javaagent/providers/AwsAttributeKeys.java | 3 + .../providers/AwsLambdaSpanProcessor.java | 55 +++++++ .../providers/AwsSpanProcessingUtil.java | 35 +++++ .../providers/AwsLambdaSpanProcessorTest.java | 140 ++++++++++++++++++ .../providers/AwsSpanProcessingUtilTest.java | 104 +++++++++++++ lambda-layer/.gitignore | 6 + 9 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessor.java create mode 100644 awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessorTest.java diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index a268380681..2255a97aca 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -256,7 +256,7 @@ jobs: aws s3 cp ./build/distributions/aws-opentelemetry-java-layer.zip s3://adot-main-build-staging-jar/adot-java-lambda-layer-${{ github.run_id }}.zip application-signals-e2e-test: - needs: [build] + needs: [build, application-signals-lambda-layer-build] uses: ./.github/workflows/application-signals-e2e-test.yml secrets: inherit with: diff --git a/.github/workflows/release-lambda.yml b/.github/workflows/release-lambda.yml index 249caa786b..87336ab4b9 100644 --- a/.github/workflows/release-lambda.yml +++ b/.github/workflows/release-lambda.yml @@ -109,7 +109,7 @@ jobs: aws lambda publish-layer-version \ --layer-name ${{ env.LAYER_NAME }} \ --content S3Bucket=${{ env.BUCKET_NAME }},S3Key=aws-opentelemetry-java-layer.zip \ - --compatible-runtimes java17 java21 \ + --compatible-runtimes java11 java17 java21 \ --compatible-architectures "arm64" "x86_64" \ --license-info "Apache-2.0" \ --description "AWS Distro of OpenTelemetry Lambda Layer for Java Runtime" \ @@ -140,7 +140,7 @@ jobs: if: ${{ success() }} uses: actions/upload-artifact@v4 with: - name: ${{ env.LAYER_NAME }} + name: ${{ env.LAYER_NAME }}-${{ matrix.aws_region }} path: ${{ env.LAYER_NAME }}/${{ matrix.aws_region }} - name: clean s3 @@ -154,13 +154,16 @@ jobs: steps: - name: Checkout Repo @ SHA - ${{ github.sha }} uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v2 + - name: download layerARNs uses: actions/download-artifact@v4 with: pattern: ${{ env.LAYER_NAME }}-* path: ${{ env.LAYER_NAME }} merge-multiple: true + - name: show layerARNs run: | for file in ${{ env.LAYER_NAME }}/* @@ -168,6 +171,7 @@ jobs: echo $file cat $file done + - name: generate layer-note working-directory: ${{ env.LAYER_NAME }} run: | 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 d6bd420475..8cdd55a881 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 @@ -283,6 +283,10 @@ private Sampler customizeSampler(Sampler sampler, ConfigProperties configProps) private SdkTracerProviderBuilder customizeTracerProviderBuilder( SdkTracerProviderBuilder tracerProviderBuilder, ConfigProperties configProps) { + if (isLambdaEnvironment()) { + tracerProviderBuilder.addSpanProcessor(new AwsLambdaSpanProcessor()); + } + if (isApplicationSignalsEnabled(configProps)) { logger.info("AWS Application Signals enabled"); Duration exportInterval = @@ -294,9 +298,27 @@ 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); + 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; diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java index 75596460d9..726979dbf2 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java @@ -97,4 +97,7 @@ private AwsAttributeKeys() {} AttributeKey.stringKey("aws.bedrock.guardrail.id"); static final AttributeKey AWS_GUARDRAIL_ARN = AttributeKey.stringKey("aws.bedrock.guardrail.arn"); + + static final AttributeKey AWS_TRACE_LAMBDA_MULTIPLE_SERVER = + AttributeKey.booleanKey("aws.trace.lambda.multiple-server"); } diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessor.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessor.java new file mode 100644 index 0000000000..65b5f6c07c --- /dev/null +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessor.java @@ -0,0 +1,55 @@ +/* + * Copyright Amazon.com, Inc. 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. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.opentelemetry.javaagent.providers; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; +import javax.annotation.concurrent.Immutable; + +@Immutable +public final class AwsLambdaSpanProcessor implements SpanProcessor { + @Override + public void onStart(Context parentContext, ReadWriteSpan span) { + if (AwsSpanProcessingUtil.isServletServerSpan(span)) { + Span parentSpan = Span.fromContextOrNull(parentContext); + if (parentSpan == null || !(parentSpan instanceof ReadWriteSpan)) { + return; + } + + ReadWriteSpan parentReadWriteSpan = (ReadWriteSpan) parentSpan; + if (!AwsSpanProcessingUtil.isLambdaServerSpan(parentReadWriteSpan)) { + return; + } + parentReadWriteSpan.setAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER, true); + } + } + + @Override + public boolean isStartRequired() { + return true; + } + + @Override + public void onEnd(ReadableSpan span) {} + + @Override + public boolean isEndRequired() { + return false; + } +} diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java index a855757075..b1f0e01b1b 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java @@ -37,6 +37,7 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.data.SpanData; import java.io.IOException; import java.io.InputStream; @@ -68,6 +69,10 @@ final class AwsSpanProcessingUtil { private static final String SQL_DIALECT_KEYWORDS_JSON = "configuration/sql_dialect_keywords.json"; + static final AttributeKey OTEL_SCOPE_NAME = AttributeKey.stringKey("otel.scope.name"); + static final String LAMBDA_SCOPE_PREFIX = "io.opentelemetry.aws-lambda-"; + static final String SERVLET_SCOPE_PREFIX = "io.opentelemetry.servlet-"; + static List getDialectKeywords() { try (InputStream jsonFile = AwsSpanProcessingUtil.class @@ -91,6 +96,10 @@ static List getDialectKeywords() { */ static String getIngressOperation(SpanData span) { if (isLambdaEnvironment()) { + String op = generateIngressOperation(span); + if (!op.equals(UNKNOWN_OPERATION)) { + return op; + } return System.getenv(AWS_LAMBDA_FUNCTION_NAME_CONFIG) + "/FunctionHandler"; } String operation = span.getName(); @@ -248,4 +257,30 @@ static boolean isDBSpan(SpanData span) { || isKeyPresent(span, DB_OPERATION) || isKeyPresent(span, DB_STATEMENT); } + + static boolean isLambdaServerSpan(ReadableSpan span) { + String scopeName = null; + if (span != null + && span.toSpanData() != null + && span.toSpanData().getInstrumentationScopeInfo() != null) { + scopeName = span.toSpanData().getInstrumentationScopeInfo().getName(); + } + + return scopeName != null + && scopeName.startsWith(LAMBDA_SCOPE_PREFIX) + && SpanKind.SERVER == span.getKind(); + } + + static boolean isServletServerSpan(ReadableSpan span) { + String scopeName = null; + if (span != null + && span.toSpanData() != null + && span.toSpanData().getInstrumentationScopeInfo() != null) { + scopeName = span.toSpanData().getInstrumentationScopeInfo().getName(); + } + + return scopeName != null + && scopeName.startsWith(SERVLET_SCOPE_PREFIX) + && SpanKind.SERVER == span.getKind(); + } } diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessorTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessorTest.java new file mode 100644 index 0000000000..19f1ae005c --- /dev/null +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsLambdaSpanProcessorTest.java @@ -0,0 +1,140 @@ +/* + * Copyright Amazon.com, Inc. 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. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.opentelemetry.javaagent.providers; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.*; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class AwsLambdaSpanProcessorTest { + + private AwsLambdaSpanProcessor processor; + private ReadWriteSpan mockLambdaServerSpan; + private SpanData mockLambdaSpanData; + private InstrumentationScopeInfo mockLambdaScopeInfo; + private Map, Object> attributeMapForLambdaSpan; + private SpanContext mockSpanContext; + + private ReadWriteSpan mockServletServerSpan; + private SpanData mockServletSpanData; + private InstrumentationScopeInfo mockServletScopeInfo; + + private Tracer lambdaTracer; + private Tracer servletTracer; + private Tracer otherTracer; + + @BeforeEach + public void setup() { + processor = new AwsLambdaSpanProcessor(); + lambdaTracer = + SdkTracerProvider.builder() + .addSpanProcessor(processor) + .build() + .get(AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "core-1.0"); + + servletTracer = + SdkTracerProvider.builder() + .addSpanProcessor(processor) + .build() + .get(AwsSpanProcessingUtil.SERVLET_SCOPE_PREFIX + "lib-3.0"); + + otherTracer = + SdkTracerProvider.builder().addSpanProcessor(processor).build().get("other-lib-2.0"); + } + + @Test + void testOnStart_servletServerSpan_withLambdaServerSpan() { + Span parentSpan = + lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.SERVER).startSpan(); + servletTracer + .spanBuilder("child-servlet") + .setSpanKind(SpanKind.SERVER) + .setParent(Context.current().with(parentSpan)) + .startSpan(); + + ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; + assertThat(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER)) + .isEqualTo(true); + } + + @Test + void testOnStart_servletInternalSpan_withLambdaServerSpan() { + Span parentSpan = + lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.SERVER).startSpan(); + + servletTracer + .spanBuilder("child-servlet") + .setSpanKind(SpanKind.INTERNAL) + .setParent(Context.current().with(parentSpan)) + .startSpan(); + + ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; + assertNull(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER)); + } + + @Test + void testOnStart_servletServerSpan_withLambdaInternalSpan() { + Span parentSpan = + lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.INTERNAL).startSpan(); + + servletTracer + .spanBuilder("child-servlet") + .setSpanKind(SpanKind.SERVER) + .setParent(Context.current().with(parentSpan)) + .startSpan(); + + ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; + assertNull(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER)); + } + + @Test + void testOnStart_servletServerSpan_withLambdaServerSpanAsGrandParent() { + Span grandParentSpan = + lambdaTracer.spanBuilder("grandparent-lambda").setSpanKind(SpanKind.SERVER).startSpan(); + + Span parentSpan = + otherTracer + .spanBuilder("parent-other") + .setSpanKind(SpanKind.SERVER) + .setParent(Context.current().with(grandParentSpan)) + .startSpan(); + + servletTracer + .spanBuilder("child-servlet") + .setSpanKind(SpanKind.SERVER) + .setParent(Context.current().with(parentSpan)) + .startSpan(); + + ReadableSpan grandParentReadableSpan = (ReadableSpan) grandParentSpan; + assertNull( + grandParentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER)); + } +} diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java index 0ed7b2d326..f3500a2aa6 100644 --- a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java @@ -19,6 +19,8 @@ import static io.opentelemetry.semconv.SemanticAttributes.MessagingOperationValues.PROCESS; import static io.opentelemetry.semconv.SemanticAttributes.MessagingOperationValues.RECEIVE; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION; @@ -29,6 +31,7 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.data.SpanData; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -403,4 +406,105 @@ public void testSqlDialectKeywordsMaxLength() { assertThat(MAX_KEYWORD_LENGTH >= keyword.length()); } } + + @Test + public void testIsLambdaServerSpan_withLambdaScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()).thenReturn(AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "-lib-1.0"); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertTrue(AwsSpanProcessingUtil.isLambdaServerSpan(span)); + } + + @Test + public void testIsLambdaServerSpan_withNonLambdaScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()) + .thenReturn("org.abc." + AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "-lib-3.0"); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertFalse(AwsSpanProcessingUtil.isLambdaServerSpan(span)); + } + + @Test + public void testIsLambdaServerSpan_withNullScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(null); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertFalse(AwsSpanProcessingUtil.isLambdaServerSpan(span)); + } + + @Test + public void testIsLambdaServerSpan_withNonServerSpanKind() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()).thenReturn(AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "-core-1.0"); + when(span.getKind()).thenReturn(SpanKind.CLIENT); + + assertFalse(AwsSpanProcessingUtil.isLambdaServerSpan(span)); + } + + @Test + public void testIsServletServerSpan_withServletScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()).thenReturn(AwsSpanProcessingUtil.SERVLET_SCOPE_PREFIX + "-3.0"); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertTrue(AwsSpanProcessingUtil.isServletServerSpan(span)); + } + + @Test + public void testIsServletServerSpan_withNonServletScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()).thenReturn(AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "-2.0"); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertFalse(AwsSpanProcessingUtil.isServletServerSpan(span)); + } + + @Test + public void testIsServletServerSpan_withNullScope() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(null); + when(span.getKind()).thenReturn(SpanKind.SERVER); + + assertFalse(AwsSpanProcessingUtil.isServletServerSpan(span)); + } + + @Test + public void testIsServletServerSpan_withNonServerSpanKind() { + ReadableSpan span = mock(ReadableSpan.class); + SpanData spanData = mock(SpanData.class); + InstrumentationScopeInfo scopeInfo = mock(InstrumentationScopeInfo.class); + when(span.toSpanData()).thenReturn(spanData); + when(spanData.getInstrumentationScopeInfo()).thenReturn(scopeInfo); + when(scopeInfo.getName()).thenReturn(AwsSpanProcessingUtil.SERVLET_SCOPE_PREFIX + "-5.0"); + when(span.getKind()).thenReturn(SpanKind.CLIENT); + + assertFalse(AwsSpanProcessingUtil.isServletServerSpan(span)); + } } diff --git a/lambda-layer/.gitignore b/lambda-layer/.gitignore index 1b6985c009..719d3e0657 100644 --- a/lambda-layer/.gitignore +++ b/lambda-layer/.gitignore @@ -3,3 +3,9 @@ # Ignore Gradle build output directory build + +# Ignore Terraform state files +.terraform/ +*.tfstate +*.tfstate.backup +*.lock.hcl \ No newline at end of file