Skip to content

Commit f2e75f7

Browse files
committed
Merge remote-tracking branch 'origin/main' into release/v2.0.x
2 parents 3aceb87 + 83e5ade commit f2e75f7

File tree

16 files changed

+715
-37
lines changed

16 files changed

+715
-37
lines changed

.github/workflows/application-signals-e2e-test.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ jobs:
205205
java-version: '11'
206206
cpu-architecture: 'arm64'
207207

208+
#
209+
# UBUNTU COVERAGE
210+
# DEFAULT SETTING: Java 11, EC2, AMD64, Ubuntu
211+
#
212+
213+
v11-amd64-ubuntu:
214+
needs: [ upload-main-build ]
215+
uses: aws-observability/aws-application-signals-test-framework/.github/workflows/java-ec2-ubuntu-test.yml@main
216+
secrets: inherit
217+
with:
218+
aws-region: us-east-1
219+
caller-workflow-name: 'main-build'
220+
208221
#
209222
# Other Functional Test Case
210223
#
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
name: Release Java Lambda layer
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: The version to tag the lambda release with, e.g., 1.2.0
8+
required: true
9+
aws_region:
10+
description: 'Deploy to aws regions'
11+
required: true
12+
default: 'us-east-1, us-east-2, us-west-1, us-west-2, ap-south-1, ap-northeast-3, ap-northeast-2, ap-southeast-1, ap-southeast-2, ap-northeast-1, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-west-3, eu-north-1, sa-east-1, af-south-1, ap-east-1, ap-south-2, ap-southeast-3, ap-southeast-4, eu-central-2, eu-south-1, eu-south-2, il-central-1, me-central-1, me-south-1'
13+
14+
env:
15+
COMMERCIAL_REGIONS: us-east-1, us-east-2, us-west-1, us-west-2, ap-south-1, ap-northeast-3, ap-northeast-2, ap-southeast-1, ap-southeast-2, ap-northeast-1, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-west-3, eu-north-1, sa-east-1
16+
LAYER_NAME: AWSOpenTelemetryDistroJava
17+
18+
permissions:
19+
id-token: write
20+
contents: write
21+
22+
jobs:
23+
build-layer:
24+
runs-on: ubuntu-latest
25+
outputs:
26+
aws_regions_json: ${{ steps.set-matrix.outputs.aws_regions_json }}
27+
steps:
28+
- name: Set up regions matrix
29+
id: set-matrix
30+
run: |
31+
IFS=',' read -ra REGIONS <<< "${{ github.event.inputs.aws_region }}"
32+
MATRIX="["
33+
for region in "${REGIONS[@]}"; do
34+
trimmed_region=$(echo "$region" | xargs)
35+
MATRIX+="\"$trimmed_region\","
36+
done
37+
MATRIX="${MATRIX%,}]"
38+
echo ${MATRIX}
39+
echo "aws_regions_json=${MATRIX}" >> $GITHUB_OUTPUT
40+
41+
- name: Checkout Repo @ SHA - ${{ github.sha }}
42+
uses: actions/checkout@v4
43+
44+
- uses: actions/setup-java@v4
45+
with:
46+
java-version: 17
47+
distribution: 'temurin'
48+
49+
- name: Build layers
50+
working-directory: lambda-layer
51+
run: |
52+
./build-layer.sh
53+
54+
- name: Upload layer
55+
uses: actions/upload-artifact@v4
56+
with:
57+
name: aws-opentelemetry-java-layer.zip
58+
path: lambda-layer/build/distributions/aws-opentelemetry-java-layer.zip
59+
60+
publish-prod:
61+
runs-on: ubuntu-latest
62+
needs: build-layer
63+
strategy:
64+
matrix:
65+
aws_region: ${{ fromJson(needs.build-layer.outputs.aws_regions_json) }}
66+
steps:
67+
- name: role arn
68+
env:
69+
COMMERCIAL_REGIONS: ${{ env.COMMERCIAL_REGIONS }}
70+
run: |
71+
COMMERCIAL_REGIONS_ARRAY=(${COMMERCIAL_REGIONS//,/ })
72+
FOUND=false
73+
for REGION in "${COMMERCIAL_REGIONS_ARRAY[@]}"; do
74+
if [[ "$REGION" == "${{ matrix.aws_region }}" ]]; then
75+
FOUND=true
76+
break
77+
fi
78+
done
79+
if [ "$FOUND" = true ]; then
80+
echo "Found ${{ matrix.aws_region }} in COMMERCIAL_REGIONS"
81+
SECRET_KEY="LAMBDA_LAYER_RELEASE"
82+
else
83+
echo "Not found ${{ matrix.aws_region }} in COMMERCIAL_REGIONS"
84+
SECRET_KEY="${{ matrix.aws_region }}_LAMBDA_LAYER_RELEASE"
85+
fi
86+
SECRET_KEY=${SECRET_KEY//-/_}
87+
echo "SECRET_KEY=${SECRET_KEY}" >> $GITHUB_ENV
88+
89+
- uses: aws-actions/[email protected]
90+
with:
91+
role-to-assume: ${{ secrets[env.SECRET_KEY] }}
92+
role-duration-seconds: 1200
93+
aws-region: ${{ matrix.aws_region }}
94+
95+
- name: Get s3 bucket name for release
96+
run: |
97+
echo BUCKET_NAME=java-lambda-layer-${{ github.run_id }}-${{ matrix.aws_region }} | tee --append $GITHUB_ENV
98+
99+
- name: download layer.zip
100+
uses: actions/download-artifact@v4
101+
with:
102+
name: aws-opentelemetry-java-layer.zip
103+
104+
- name: publish
105+
run: |
106+
aws s3 mb s3://${{ env.BUCKET_NAME }}
107+
aws s3 cp aws-opentelemetry-java-layer.zip s3://${{ env.BUCKET_NAME }}
108+
layerARN=$(
109+
aws lambda publish-layer-version \
110+
--layer-name ${{ env.LAYER_NAME }} \
111+
--content S3Bucket=${{ env.BUCKET_NAME }},S3Key=aws-opentelemetry-java-layer.zip \
112+
--compatible-runtimes java17 java21 \
113+
--compatible-architectures "arm64" "x86_64" \
114+
--license-info "Apache-2.0" \
115+
--description "AWS Distro of OpenTelemetry Lambda Layer for Java Runtime" \
116+
--query 'LayerVersionArn' \
117+
--output text
118+
)
119+
echo $layerARN
120+
echo "LAYER_ARN=${layerARN}" >> $GITHUB_ENV
121+
mkdir ${{ env.LAYER_NAME }}
122+
echo $layerARN > ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
123+
cat ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
124+
125+
- name: public layer
126+
run: |
127+
layerVersion=$(
128+
aws lambda list-layer-versions \
129+
--layer-name ${{ env.LAYER_NAME }} \
130+
--query 'max_by(LayerVersions, &Version).Version'
131+
)
132+
aws lambda add-layer-version-permission \
133+
--layer-name ${{ env.LAYER_NAME }} \
134+
--version-number $layerVersion \
135+
--principal "*" \
136+
--statement-id publish \
137+
--action lambda:GetLayerVersion
138+
139+
- name: upload layer arn artifact
140+
if: ${{ success() }}
141+
uses: actions/upload-artifact@v4
142+
with:
143+
name: ${{ env.LAYER_NAME }}
144+
path: ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
145+
146+
- name: clean s3
147+
if: always()
148+
run: |
149+
aws s3 rb --force s3://${{ env.BUCKET_NAME }}
150+
151+
generate-release-note:
152+
runs-on: ubuntu-latest
153+
needs: publish-prod
154+
steps:
155+
- name: Checkout Repo @ SHA - ${{ github.sha }}
156+
uses: actions/checkout@v4
157+
158+
- uses: hashicorp/setup-terraform@v2
159+
160+
- name: download layerARNs
161+
uses: actions/download-artifact@v4
162+
with:
163+
name: ${{ env.LAYER_NAME }}
164+
path: ${{ env.LAYER_NAME }}
165+
166+
- name: show layerARNs
167+
run: |
168+
for file in ${{ env.LAYER_NAME }}/*
169+
do
170+
echo $file
171+
cat $file
172+
done
173+
174+
- name: generate layer-note
175+
working-directory: ${{ env.LAYER_NAME }}
176+
run: |
177+
echo "| Region | Layer ARN |" >> ../layer-note
178+
echo "| ---- | ---- |" >> ../layer-note
179+
for file in *
180+
do
181+
read arn < $file
182+
echo "| " $file " | " $arn " |" >> ../layer-note
183+
done
184+
cd ..
185+
cat layer-note
186+
187+
- name: generate tf layer
188+
working-directory: ${{ env.LAYER_NAME }}
189+
run: |
190+
echo "locals {" >> ../layer.tf
191+
echo " sdk_layer_arns = {" >> ../layer.tf
192+
for file in *
193+
do
194+
read arn < $file
195+
echo " \""$file"\" = \""$arn"\"" >> ../layer.tf
196+
done
197+
cd ..
198+
echo " }" >> layer.tf
199+
echo "}" >> layer.tf
200+
terraform fmt layer.tf
201+
cat layer.tf
202+
203+
- name: upload layer tf file
204+
uses: actions/upload-artifact@v4
205+
with:
206+
name: layer.tf
207+
path: layer.tf
208+
209+
- name: Create GH release
210+
id: create_release
211+
env:
212+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
213+
run: |
214+
gh release create --target "$GITHUB_REF_NAME" \
215+
--title "Release lambda-v${{ github.event.inputs.version }}" \
216+
--draft \
217+
"lambda-v${{ github.event.inputs.version }}" \
218+
layer.tf

appsignals-tests/images/grpc/grpc-base/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protobuf {
3636
}
3737
plugins {
3838
create("grpc") {
39-
artifact = "io.grpc:protoc-gen-grpc-java:1.56.1"
39+
artifact = "io.grpc:protoc-gen-grpc-java:1.69.1"
4040
}
4141
}
4242
generateProtoTasks {

awsagentprovider/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ dependencies {
4141
// Import AWS SDK v1 core for ARN parsing utilities
4242
implementation("com.amazonaws:aws-java-sdk-core:1.12.773")
4343
// Export configuration
44-
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp")
44+
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
4545
// For Udp emitter
4646
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp-common")
47+
// For HTTP SigV4 emitter
48+
implementation("software.amazon.awssdk:auth:2.30.14")
49+
implementation("software.amazon.awssdk:http-auth-aws:2.30.14")
4750

4851
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
4952
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
2626
() ->
2727
new HashMap<String, String>() {
2828
{
29-
put("otel.propagators", "xray,tracecontext,b3,b3multi");
29+
put("otel.propagators", "baggage,xray,tracecontext,b3,b3multi");
3030
put("otel.instrumentation.aws-sdk.experimental-span-attributes", "true");
3131
put(
3232
"otel.instrumentation.aws-sdk.experimental-record-individual-http-error",

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import java.util.Set;
5252
import java.util.logging.Level;
5353
import java.util.logging.Logger;
54+
import java.util.regex.Pattern;
5455

5556
/**
5657
* This customizer performs the following customizations:
@@ -70,6 +71,8 @@
7071
public class AwsApplicationSignalsCustomizerProvider
7172
implements AutoConfigurationCustomizerProvider {
7273
static final String AWS_LAMBDA_FUNCTION_NAME_CONFIG = "AWS_LAMBDA_FUNCTION_NAME";
74+
private static final String XRAY_OTLP_ENDPOINT_PATTERN =
75+
"^https://xray\\.([a-z0-9-]+)\\.amazonaws\\.com/v1/traces$";
7376

7477
private static final Duration DEFAULT_METRIC_EXPORT_INTERVAL = Duration.ofMinutes(1);
7578
private static final Logger logger =
@@ -121,6 +124,16 @@ static boolean isLambdaEnvironment() {
121124
return System.getenv(AWS_LAMBDA_FUNCTION_NAME_CONFIG) != null;
122125
}
123126

127+
static boolean isXrayOtlpEndpoint(String otlpEndpoint) {
128+
if (otlpEndpoint == null) {
129+
return false;
130+
}
131+
132+
return Pattern.compile(XRAY_OTLP_ENDPOINT_PATTERN)
133+
.matcher(otlpEndpoint.toLowerCase())
134+
.matches();
135+
}
136+
124137
private boolean isApplicationSignalsEnabled(ConfigProperties configProps) {
125138
return configProps.getBoolean(
126139
APPLICATION_SIGNALS_ENABLED_CONFIG,
@@ -221,6 +234,10 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
221234
return tracerProviderBuilder;
222235
}
223236

237+
if (isXrayOtlpEndpoint(System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG))) {
238+
return tracerProviderBuilder;
239+
}
240+
224241
// Construct meterProvider
225242
MetricExporter metricsExporter =
226243
ApplicationSignalsExporterProvider.INSTANCE.createExporter(configProps);
@@ -286,6 +303,14 @@ private SpanExporter customizeSpanExporter(
286303
.build();
287304
}
288305
}
306+
// When running OTLP endpoint for X-Ray backend, use custom exporter for SigV4 authentication
307+
else if (spanExporter instanceof OtlpHttpSpanExporter
308+
&& isXrayOtlpEndpoint(System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG))) {
309+
spanExporter =
310+
new OtlpAwsSpanExporter(
311+
(OtlpHttpSpanExporter) spanExporter,
312+
System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG));
313+
}
289314

290315
if (isApplicationSignalsEnabled(configProps)) {
291316
return AwsMetricAttributesSpanExporterBuilder.create(

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_STATUS_CODE;
1919
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE;
20+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
2021
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;
2122

2223
import io.opentelemetry.api.common.Attributes;
@@ -61,6 +62,10 @@ public final class AwsSpanMetricsProcessor implements SpanProcessor {
6162
private static final int FAULT_CODE_LOWER_BOUND = 500;
6263
private static final int FAULT_CODE_UPPER_BOUND = 599;
6364

65+
// EC2 Metadata API IP Address
66+
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#instancedata-inside-access
67+
private final String EC2_METADATA_API_IP = "169.254.169.254";
68+
6469
// Metric instruments
6570
private final LongHistogram errorHistogram;
6671
private final LongHistogram faultHistogram;
@@ -172,9 +177,18 @@ private void recordLatency(ReadableSpan span, Attributes attributes) {
172177

173178
private void recordMetrics(ReadableSpan span, SpanData spanData, Attributes attributes) {
174179
// Only record metrics if non-empty attributes are returned.
175-
if (!attributes.isEmpty()) {
180+
if (!attributes.isEmpty() && !isEc2MetadataSpan((attributes))) {
176181
recordErrorOrFault(spanData, attributes);
177182
recordLatency(span, attributes);
178183
}
179184
}
185+
186+
private boolean isEc2MetadataSpan(Attributes attributes) {
187+
if (attributes.get(AWS_REMOTE_SERVICE) != null
188+
&& attributes.get(AWS_REMOTE_SERVICE).equals(EC2_METADATA_API_IP)) {
189+
return true;
190+
}
191+
192+
return false;
193+
}
180194
}

0 commit comments

Comments
 (0)