Skip to content

Commit c67a62d

Browse files
committed
[Lambda Java] Merge All Code Changes from v1.33 Branch into Main
This change merges all private Lambda Java updates from the v1.33 branch into the main branch. I performed a 'git rebase main' 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 main branch (excluding this PR). 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 #1076
1 parent 24c2618 commit c67a62d

File tree

11 files changed

+370
-5
lines changed

11 files changed

+370
-5
lines changed

.github/workflows/main-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ jobs:
256256
aws s3 cp ./build/distributions/aws-opentelemetry-java-layer.zip s3://adot-main-build-staging-jar/adot-java-lambda-layer-${{ github.run_id }}.zip
257257
258258
application-signals-e2e-test:
259-
needs: [build]
259+
needs: [build, application-signals-lambda-layer-build]
260260
uses: ./.github/workflows/application-signals-e2e-test.yml
261261
secrets: inherit
262262
with:

.github/workflows/release-lambda.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ jobs:
110110
aws lambda publish-layer-version \
111111
--layer-name ${{ env.LAYER_NAME }} \
112112
--content S3Bucket=${{ env.BUCKET_NAME }},S3Key=aws-opentelemetry-java-layer.zip \
113-
--compatible-runtimes java17 java21 \
113+
--compatible-runtimes java11 java17 java21 \
114114
--compatible-architectures "arm64" "x86_64" \
115115
--license-info "Apache-2.0" \
116116
--description "AWS Distro of OpenTelemetry Lambda Layer for Java Runtime" \

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ private Sampler customizeSampler(Sampler sampler, ConfigProperties configProps)
289289

290290
private SdkTracerProviderBuilder customizeTracerProviderBuilder(
291291
SdkTracerProviderBuilder tracerProviderBuilder, ConfigProperties configProps) {
292+
if (isLambdaEnvironment()) {
293+
tracerProviderBuilder.addSpanProcessor(new AwsLambdaSpanProcessor());
294+
}
295+
292296
if (isApplicationSignalsEnabled(configProps)) {
293297
logger.info("AWS Application Signals enabled");
294298
Duration exportInterval =
@@ -300,9 +304,27 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
300304

301305
// If running on Lambda, we just need to export 100% spans and skip generating any Application
302306
// Signals metrics.
303-
if (isLambdaEnvironment()) {
307+
if (isLambdaEnvironment()
308+
&& System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG) == null) {
309+
String tracesEndpoint =
310+
Optional.ofNullable(System.getenv(AWS_XRAY_DAEMON_ADDRESS_CONFIG))
311+
.orElse(DEFAULT_UDP_ENDPOINT);
312+
SpanExporter spanExporter =
313+
new OtlpUdpSpanExporterBuilder()
314+
.setPayloadSampleDecision(TracePayloadSampleDecision.UNSAMPLED)
315+
.setEndpoint(tracesEndpoint)
316+
.build();
317+
318+
// Wrap the udp exporter with the AwsMetricsAttributesSpanExporter to add Application
319+
// Signals attributes to unsampled spans too
320+
SpanExporter appSignalsSpanExporter =
321+
AwsMetricAttributesSpanExporterBuilder.create(
322+
spanExporter, ResourceHolder.getResource())
323+
.build();
324+
304325
tracerProviderBuilder.addSpanProcessor(
305326
AwsUnsampledOnlySpanProcessorBuilder.create()
327+
.setSpanExporter(appSignalsSpanExporter)
306328
.setMaxExportBatchSize(LAMBDA_SPAN_EXPORT_BATCH_SIZE)
307329
.build());
308330
return tracerProviderBuilder;

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,7 @@ private AwsAttributeKeys() {}
126126
AttributeKey.stringKey("aws.bedrock.guardrail.id");
127127
static final AttributeKey<String> AWS_GUARDRAIL_ARN =
128128
AttributeKey.stringKey("aws.bedrock.guardrail.arn");
129+
130+
static final AttributeKey<Boolean> AWS_TRACE_LAMBDA_MULTIPLE_SERVER =
131+
AttributeKey.booleanKey("aws.trace.lambda.multiple-server");
129132
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.opentelemetry.javaagent.providers;
17+
18+
import io.opentelemetry.api.trace.Span;
19+
import io.opentelemetry.context.Context;
20+
import io.opentelemetry.sdk.trace.ReadWriteSpan;
21+
import io.opentelemetry.sdk.trace.ReadableSpan;
22+
import io.opentelemetry.sdk.trace.SpanProcessor;
23+
import javax.annotation.concurrent.Immutable;
24+
25+
@Immutable
26+
public final class AwsLambdaSpanProcessor implements SpanProcessor {
27+
@Override
28+
public void onStart(Context parentContext, ReadWriteSpan span) {
29+
if (AwsSpanProcessingUtil.isServletServerSpan(span)) {
30+
Span parentSpan = Span.fromContextOrNull(parentContext);
31+
if (parentSpan == null || !(parentSpan instanceof ReadWriteSpan)) {
32+
return;
33+
}
34+
35+
ReadWriteSpan parentReadWriteSpan = (ReadWriteSpan) parentSpan;
36+
if (!AwsSpanProcessingUtil.isLambdaServerSpan(parentReadWriteSpan)) {
37+
return;
38+
}
39+
parentReadWriteSpan.setAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER, true);
40+
}
41+
}
42+
43+
@Override
44+
public boolean isStartRequired() {
45+
return true;
46+
}
47+
48+
@Override
49+
public void onEnd(ReadableSpan span) {}
50+
51+
@Override
52+
public boolean isEndRequired() {
53+
return false;
54+
}
55+
}

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import io.opentelemetry.api.trace.SpanContext;
4040
import io.opentelemetry.api.trace.SpanKind;
4141
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
42+
import io.opentelemetry.sdk.trace.ReadableSpan;
4243
import io.opentelemetry.sdk.trace.data.SpanData;
4344
import java.io.IOException;
4445
import java.io.InputStream;
@@ -70,6 +71,10 @@ final class AwsSpanProcessingUtil {
7071

7172
private static final String SQL_DIALECT_KEYWORDS_JSON = "configuration/sql_dialect_keywords.json";
7273

74+
static final AttributeKey<String> OTEL_SCOPE_NAME = AttributeKey.stringKey("otel.scope.name");
75+
static final String LAMBDA_SCOPE_PREFIX = "io.opentelemetry.aws-lambda-";
76+
static final String SERVLET_SCOPE_PREFIX = "io.opentelemetry.servlet-";
77+
7378
static List<String> getDialectKeywords() {
7479
try (InputStream jsonFile =
7580
AwsSpanProcessingUtil.class
@@ -109,6 +114,10 @@ static String getIngressOperation(SpanData span) {
109114
if (operationOverride != null) {
110115
return operationOverride;
111116
}
117+
String op = generateIngressOperation(span);
118+
if (!op.equals(UNKNOWN_OPERATION)) {
119+
return op;
120+
}
112121
return getFunctionNameFromEnv() + "/FunctionHandler";
113122
}
114123
String operation = span.getName();
@@ -290,4 +299,30 @@ static boolean isDBSpan(SpanData span) {
290299
|| isKeyPresent(span, DB_OPERATION)
291300
|| isKeyPresent(span, DB_STATEMENT);
292301
}
302+
303+
static boolean isLambdaServerSpan(ReadableSpan span) {
304+
String scopeName = null;
305+
if (span != null
306+
&& span.toSpanData() != null
307+
&& span.toSpanData().getInstrumentationScopeInfo() != null) {
308+
scopeName = span.toSpanData().getInstrumentationScopeInfo().getName();
309+
}
310+
311+
return scopeName != null
312+
&& scopeName.startsWith(LAMBDA_SCOPE_PREFIX)
313+
&& SpanKind.SERVER == span.getKind();
314+
}
315+
316+
static boolean isServletServerSpan(ReadableSpan span) {
317+
String scopeName = null;
318+
if (span != null
319+
&& span.toSpanData() != null
320+
&& span.toSpanData().getInstrumentationScopeInfo() != null) {
321+
scopeName = span.toSpanData().getInstrumentationScopeInfo().getName();
322+
}
323+
324+
return scopeName != null
325+
&& scopeName.startsWith(SERVLET_SCOPE_PREFIX)
326+
&& SpanKind.SERVER == span.getKind();
327+
}
293328
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.opentelemetry.javaagent.providers;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.api.Assertions.assertNull;
20+
import static org.mockito.Mockito.*;
21+
22+
import io.opentelemetry.api.common.AttributeKey;
23+
import io.opentelemetry.api.trace.Span;
24+
import io.opentelemetry.api.trace.SpanContext;
25+
import io.opentelemetry.api.trace.SpanKind;
26+
import io.opentelemetry.api.trace.Tracer;
27+
import io.opentelemetry.context.Context;
28+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
29+
import io.opentelemetry.sdk.trace.ReadWriteSpan;
30+
import io.opentelemetry.sdk.trace.ReadableSpan;
31+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
32+
import io.opentelemetry.sdk.trace.data.SpanData;
33+
import java.util.Map;
34+
import org.junit.jupiter.api.BeforeEach;
35+
import org.junit.jupiter.api.Test;
36+
37+
class AwsLambdaSpanProcessorTest {
38+
39+
private AwsLambdaSpanProcessor processor;
40+
private ReadWriteSpan mockLambdaServerSpan;
41+
private SpanData mockLambdaSpanData;
42+
private InstrumentationScopeInfo mockLambdaScopeInfo;
43+
private Map<AttributeKey<?>, Object> attributeMapForLambdaSpan;
44+
private SpanContext mockSpanContext;
45+
46+
private ReadWriteSpan mockServletServerSpan;
47+
private SpanData mockServletSpanData;
48+
private InstrumentationScopeInfo mockServletScopeInfo;
49+
50+
private Tracer lambdaTracer;
51+
private Tracer servletTracer;
52+
private Tracer otherTracer;
53+
54+
@BeforeEach
55+
public void setup() {
56+
processor = new AwsLambdaSpanProcessor();
57+
lambdaTracer =
58+
SdkTracerProvider.builder()
59+
.addSpanProcessor(processor)
60+
.build()
61+
.get(AwsSpanProcessingUtil.LAMBDA_SCOPE_PREFIX + "core-1.0");
62+
63+
servletTracer =
64+
SdkTracerProvider.builder()
65+
.addSpanProcessor(processor)
66+
.build()
67+
.get(AwsSpanProcessingUtil.SERVLET_SCOPE_PREFIX + "lib-3.0");
68+
69+
otherTracer =
70+
SdkTracerProvider.builder().addSpanProcessor(processor).build().get("other-lib-2.0");
71+
}
72+
73+
@Test
74+
void testOnStart_servletServerSpan_withLambdaServerSpan() {
75+
Span parentSpan =
76+
lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.SERVER).startSpan();
77+
servletTracer
78+
.spanBuilder("child-servlet")
79+
.setSpanKind(SpanKind.SERVER)
80+
.setParent(Context.current().with(parentSpan))
81+
.startSpan();
82+
83+
ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan;
84+
assertThat(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER))
85+
.isEqualTo(true);
86+
}
87+
88+
@Test
89+
void testOnStart_servletInternalSpan_withLambdaServerSpan() {
90+
Span parentSpan =
91+
lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.SERVER).startSpan();
92+
93+
servletTracer
94+
.spanBuilder("child-servlet")
95+
.setSpanKind(SpanKind.INTERNAL)
96+
.setParent(Context.current().with(parentSpan))
97+
.startSpan();
98+
99+
ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan;
100+
assertNull(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER));
101+
}
102+
103+
@Test
104+
void testOnStart_servletServerSpan_withLambdaInternalSpan() {
105+
Span parentSpan =
106+
lambdaTracer.spanBuilder("parent-lambda").setSpanKind(SpanKind.INTERNAL).startSpan();
107+
108+
servletTracer
109+
.spanBuilder("child-servlet")
110+
.setSpanKind(SpanKind.SERVER)
111+
.setParent(Context.current().with(parentSpan))
112+
.startSpan();
113+
114+
ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan;
115+
assertNull(parentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER));
116+
}
117+
118+
@Test
119+
void testOnStart_servletServerSpan_withLambdaServerSpanAsGrandParent() {
120+
Span grandParentSpan =
121+
lambdaTracer.spanBuilder("grandparent-lambda").setSpanKind(SpanKind.SERVER).startSpan();
122+
123+
Span parentSpan =
124+
otherTracer
125+
.spanBuilder("parent-other")
126+
.setSpanKind(SpanKind.SERVER)
127+
.setParent(Context.current().with(grandParentSpan))
128+
.startSpan();
129+
130+
servletTracer
131+
.spanBuilder("child-servlet")
132+
.setSpanKind(SpanKind.SERVER)
133+
.setParent(Context.current().with(parentSpan))
134+
.startSpan();
135+
136+
ReadableSpan grandParentReadableSpan = (ReadableSpan) grandParentSpan;
137+
assertNull(
138+
grandParentReadableSpan.getAttribute(AwsAttributeKeys.AWS_TRACE_LAMBDA_MULTIPLE_SERVER));
139+
}
140+
}

0 commit comments

Comments
 (0)