Skip to content

[Lambda Java v2.11.x] Merge All Code Changes from v1.33.x Branch into v2.11.x #1114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: release/v2.11.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/release-lambda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down Expand Up @@ -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
Expand All @@ -154,20 +154,24 @@ 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 }}/*
do
echo $file
cat $file
done

- name: generate layer-note
working-directory: ${{ env.LAYER_NAME }}
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,7 @@ private AwsAttributeKeys() {}
AttributeKey.stringKey("aws.bedrock.guardrail.id");
static final AttributeKey<String> AWS_GUARDRAIL_ARN =
AttributeKey.stringKey("aws.bedrock.guardrail.arn");

static final AttributeKey<Boolean> AWS_TRACE_LAMBDA_MULTIPLE_SERVER =
AttributeKey.booleanKey("aws.trace.lambda.multiple-server");
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -68,6 +69,10 @@ final class AwsSpanProcessingUtil {

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

static final AttributeKey<String> 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<String> getDialectKeywords() {
try (InputStream jsonFile =
AwsSpanProcessingUtil.class
Expand All @@ -91,6 +96,10 @@ static List<String> 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();
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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<AttributeKey<?>, 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));
}
}
Loading
Loading