Skip to content

Commit b8967ad

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 93440a7 commit b8967ad

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
@@ -283,6 +283,10 @@ private Sampler customizeSampler(Sampler sampler, ConfigProperties configProps)
283283

284284
private SdkTracerProviderBuilder customizeTracerProviderBuilder(
285285
SdkTracerProviderBuilder tracerProviderBuilder, ConfigProperties configProps) {
286+
if (isLambdaEnvironment()) {
287+
tracerProviderBuilder.addSpanProcessor(new AwsLambdaSpanProcessor());
288+
}
289+
286290
if (isApplicationSignalsEnabled(configProps)) {
287291
logger.info("AWS Application Signals enabled");
288292
Duration exportInterval =
@@ -294,9 +298,27 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
294298

295299
// If running on Lambda, we just need to export 100% spans and skip generating any Application
296300
// Signals metrics.
297-
if (isLambdaEnvironment()) {
301+
if (isLambdaEnvironment()
302+
&& System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG) == null) {
303+
String tracesEndpoint =
304+
Optional.ofNullable(System.getenv(AWS_XRAY_DAEMON_ADDRESS_CONFIG))
305+
.orElse(DEFAULT_UDP_ENDPOINT);
306+
SpanExporter spanExporter =
307+
new OtlpUdpSpanExporterBuilder()
308+
.setPayloadSampleDecision(TracePayloadSampleDecision.UNSAMPLED)
309+
.setEndpoint(tracesEndpoint)
310+
.build();
311+
312+
// Wrap the udp exporter with the AwsMetricsAttributesSpanExporter to add Application
313+
// Signals attributes to unsampled spans too
314+
SpanExporter appSignalsSpanExporter =
315+
AwsMetricAttributesSpanExporterBuilder.create(
316+
spanExporter, ResourceHolder.getResource())
317+
.build();
318+
298319
tracerProviderBuilder.addSpanProcessor(
299320
AwsUnsampledOnlySpanProcessorBuilder.create()
321+
.setSpanExporter(appSignalsSpanExporter)
300322
.setMaxExportBatchSize(LAMBDA_SPAN_EXPORT_BATCH_SIZE)
301323
.build());
302324
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
@@ -110,4 +110,7 @@ private AwsAttributeKeys() {}
110110
AttributeKey.stringKey("aws.bedrock.guardrail.id");
111111
static final AttributeKey<String> AWS_GUARDRAIL_ARN =
112112
AttributeKey.stringKey("aws.bedrock.guardrail.arn");
113+
114+
static final AttributeKey<Boolean> AWS_TRACE_LAMBDA_MULTIPLE_SERVER =
115+
AttributeKey.booleanKey("aws.trace.lambda.multiple-server");
113116
}
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
@@ -38,6 +38,7 @@
3838
import io.opentelemetry.api.trace.SpanContext;
3939
import io.opentelemetry.api.trace.SpanKind;
4040
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
41+
import io.opentelemetry.sdk.trace.ReadableSpan;
4142
import io.opentelemetry.sdk.trace.data.SpanData;
4243
import java.io.IOException;
4344
import java.io.InputStream;
@@ -69,6 +70,10 @@ final class AwsSpanProcessingUtil {
6970

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

73+
static final AttributeKey<String> OTEL_SCOPE_NAME = AttributeKey.stringKey("otel.scope.name");
74+
static final String LAMBDA_SCOPE_PREFIX = "io.opentelemetry.aws-lambda-";
75+
static final String SERVLET_SCOPE_PREFIX = "io.opentelemetry.servlet-";
76+
7277
static List<String> getDialectKeywords() {
7378
try (InputStream jsonFile =
7479
AwsSpanProcessingUtil.class
@@ -108,6 +113,10 @@ static String getIngressOperation(SpanData span) {
108113
if (operationOverride != null) {
109114
return operationOverride;
110115
}
116+
String op = generateIngressOperation(span);
117+
if (!op.equals(UNKNOWN_OPERATION)) {
118+
return op;
119+
}
111120
return getFunctionNameFromEnv() + "/FunctionHandler";
112121
}
113122
String operation = span.getName();
@@ -270,4 +279,30 @@ static boolean isDBSpan(SpanData span) {
270279
|| isKeyPresent(span, DB_OPERATION)
271280
|| isKeyPresent(span, DB_STATEMENT);
272281
}
282+
283+
static boolean isLambdaServerSpan(ReadableSpan span) {
284+
String scopeName = null;
285+
if (span != null
286+
&& span.toSpanData() != null
287+
&& span.toSpanData().getInstrumentationScopeInfo() != null) {
288+
scopeName = span.toSpanData().getInstrumentationScopeInfo().getName();
289+
}
290+
291+
return scopeName != null
292+
&& scopeName.startsWith(LAMBDA_SCOPE_PREFIX)
293+
&& SpanKind.SERVER == span.getKind();
294+
}
295+
296+
static boolean isServletServerSpan(ReadableSpan span) {
297+
String scopeName = null;
298+
if (span != null
299+
&& span.toSpanData() != null
300+
&& span.toSpanData().getInstrumentationScopeInfo() != null) {
301+
scopeName = span.toSpanData().getInstrumentationScopeInfo().getName();
302+
}
303+
304+
return scopeName != null
305+
&& scopeName.startsWith(SERVLET_SCOPE_PREFIX)
306+
&& SpanKind.SERVER == span.getKind();
307+
}
273308
}
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)