Skip to content

Commit 8542b29

Browse files
authored
Merge branch 'main' into java-version-pr-foo
2 parents e184dac + 6d9b13a commit 8542b29

File tree

13 files changed

+372
-7
lines changed

13 files changed

+372
-7
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" \

appsignals-tests/images/kafka/kafka-consumers/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ dependencies {
3131
implementation("org.slf4j:slf4j-api:2.0.9")
3232
implementation("org.slf4j:slf4j-simple:2.0.9")
3333
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
34-
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")
34+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.13.4")
3535
}
3636

3737
tasks.getByName<Test>("test") {

appsignals-tests/images/kafka/kafka-producers/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ dependencies {
3131
implementation("org.slf4j:slf4j-api:2.0.9")
3232
implementation("org.slf4j:slf4j-simple:2.0.9")
3333
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
34-
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")
34+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.13.4")
3535
}
3636

3737
tasks.getByName<Test>("test") {

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
}
Lines changed: 55 additions & 0 deletions
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
}
Lines changed: 140 additions & 0 deletions
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)