Skip to content

Commit 03d99f7

Browse files
committed
added copier constructor
1 parent fc76008 commit 03d99f7

File tree

3 files changed

+75
-19
lines changed

3 files changed

+75
-19
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public class AwsApplicationSignalsCustomizerProvider
7272
implements AutoConfigurationCustomizerProvider {
7373
static final String AWS_LAMBDA_FUNCTION_NAME_CONFIG = "AWS_LAMBDA_FUNCTION_NAME";
7474
private static final String XRAY_OTLP_ENDPOINT_PATTERN =
75-
"https://xray\\.([a-z0-9-]+)\\.amazonaws\\.com/v1/traces$";
75+
"^https://xray\\.([a-z0-9-]+)\\.amazonaws\\.com/v1/traces$";
7676

7777
private static final Duration DEFAULT_METRIC_EXPORT_INTERVAL = Duration.ofMinutes(1);
7878
private static final Logger logger =
@@ -307,7 +307,9 @@ private SpanExporter customizeSpanExporter(
307307
else if (spanExporter instanceof OtlpHttpSpanExporter
308308
&& isXrayOtlpEndpoint(System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG))) {
309309
spanExporter =
310-
new OtlpAwsSpanExporter(System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG));
310+
new OtlpAwsSpanExporter(
311+
(OtlpHttpSpanExporter) spanExporter,
312+
System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG));
311313
}
312314

313315
if (isApplicationSignalsEnabled(configProps)) {

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

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@
2020
import io.opentelemetry.sdk.common.CompletableResultCode;
2121
import io.opentelemetry.sdk.trace.data.SpanData;
2222
import io.opentelemetry.sdk.trace.export.SpanExporter;
23-
import java.io.*;
23+
import java.io.ByteArrayInputStream;
24+
import java.io.ByteArrayOutputStream;
2425
import java.net.URI;
25-
import java.util.*;
26+
import java.util.ArrayList;
27+
import java.util.Collection;
28+
import java.util.HashMap;
29+
import java.util.List;
30+
import java.util.Map;
2631
import java.util.function.Supplier;
2732
import javax.annotation.concurrent.Immutable;
2833
import org.slf4j.Logger;
@@ -38,13 +43,12 @@
3843
/**
3944
* This exporter extends the functionality of the OtlpHttpSpanExporter to allow spans to be exported
4045
* to the XRay OTLP endpoint https://xray.[AWSRegion].amazonaws.com/v1/traces. Utilizes the AWSSDK
41-
* library to sign and directly inject SigV4 Authentication to the exported request's headers.
42-
* https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html
46+
* library to sign and directly inject SigV4 Authentication to the exported request's headers. <a
47+
* href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html">...</a>
4348
*/
4449
@Immutable
4550
public class OtlpAwsSpanExporter implements SpanExporter {
4651
private static final Logger logger = LoggerFactory.getLogger(OtlpAwsSpanExporter.class);
47-
private static final AwsV4HttpSigner signer = AwsV4HttpSigner.create();
4852

4953
private final OtlpHttpSpanExporter parentExporter;
5054
private final String awsRegion;
@@ -63,6 +67,18 @@ public OtlpAwsSpanExporter(String endpoint) {
6367
this.spanData = new ArrayList<>();
6468
}
6569

70+
public OtlpAwsSpanExporter(OtlpHttpSpanExporter parentExporter, String endpoint) {
71+
this.parentExporter =
72+
parentExporter.toBuilder()
73+
.setEndpoint(endpoint)
74+
.setHeaders(new SigV4AuthHeaderSupplier())
75+
.build();
76+
77+
this.awsRegion = endpoint.split("\\.")[1];
78+
this.endpoint = endpoint;
79+
this.spanData = new ArrayList<>();
80+
}
81+
6682
/**
6783
* Overrides the upstream implementation of export. All behaviors are the same except if the
6884
* endpoint is an XRay OTLP endpoint, we will sign the request with SigV4 in headers before
@@ -108,14 +124,15 @@ public Map<String, String> get() {
108124
AwsCredentials credentials = DefaultCredentialsProvider.create().resolveCredentials();
109125

110126
SignedRequest signedRequest =
111-
signer.sign(
112-
b ->
113-
b.identity(credentials)
114-
.request(httpRequest)
115-
.putProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, "xray")
116-
.putProperty(
117-
AwsV4HttpSigner.REGION_NAME, OtlpAwsSpanExporter.this.awsRegion)
118-
.payload(() -> new ByteArrayInputStream(encodedSpans.toByteArray())));
127+
AwsV4HttpSigner.create()
128+
.sign(
129+
b ->
130+
b.identity(credentials)
131+
.request(httpRequest)
132+
.putProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, "xray")
133+
.putProperty(
134+
AwsV4HttpSigner.REGION_NAME, OtlpAwsSpanExporter.this.awsRegion)
135+
.payload(() -> new ByteArrayInputStream(encodedSpans.toByteArray())));
119136

120137
Map<String, String> result = new HashMap<>();
121138

awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/OtlpAwsSpanExporterTest.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public class OtlpAwsSpanExporterTest {
6767
.method(SdkHttpMethod.POST)
6868
.uri(URI.create(OTLP_CW_ENDPOINT))
6969
.putHeader(AUTHORIZATION_HEADER, EXPECTED_AUTH_HEADER)
70-
.putHeader("X-Amz-Date", EXPECTED_AUTH_X_AMZ_DATE)
71-
.putHeader("X-Amz-Security-Token", EXPECTED_AUTH_SECURITY_TOKEN)
70+
.putHeader(X_AMZ_DATE_HEADER, EXPECTED_AUTH_X_AMZ_DATE)
71+
.putHeader(X_AMZ_SECURITY_TOKEN_HEADER, EXPECTED_AUTH_SECURITY_TOKEN)
7272
.build())
7373
.build();
7474

@@ -115,12 +115,11 @@ void afterEach() {
115115
@Test
116116
void testAwsSpanExporterAddsSigV4Headers() {
117117

118+
SpanExporter exporter = new OtlpAwsSpanExporter(OTLP_CW_ENDPOINT);
118119
when(this.credentialsProvider.resolveCredentials()).thenReturn(this.credentials);
119120
when(this.signer.sign((Consumer<Builder<AwsCredentialsIdentity>>) any()))
120121
.thenReturn(this.signedRequest);
121122

122-
SpanExporter exporter = new OtlpAwsSpanExporter(OTLP_CW_ENDPOINT);
123-
124123
exporter.export(List.of());
125124

126125
Map<String, String> headers = this.headersCaptor.getValue().get();
@@ -134,6 +133,44 @@ void testAwsSpanExporterAddsSigV4Headers() {
134133
assertEquals(EXPECTED_AUTH_SECURITY_TOKEN, headers.get(X_AMZ_SECURITY_TOKEN_HEADER));
135134
}
136135

136+
@Test
137+
void testAwsSpanExporterExportCorrectlyAddsDifferentSigV4Headers() {
138+
SpanExporter exporter = new OtlpAwsSpanExporter(OTLP_CW_ENDPOINT);
139+
140+
for (int i = 0; i < 10; i += 1) {
141+
String newAuthHeader = EXPECTED_AUTH_HEADER + i;
142+
String newXAmzDate = EXPECTED_AUTH_X_AMZ_DATE + i;
143+
String newXAmzSecurityToken = EXPECTED_AUTH_SECURITY_TOKEN + i;
144+
145+
SignedRequest newSignedRequest =
146+
SignedRequest.builder()
147+
.request(
148+
SdkHttpFullRequest.builder()
149+
.method(SdkHttpMethod.POST)
150+
.uri(URI.create(OTLP_CW_ENDPOINT))
151+
.putHeader(AUTHORIZATION_HEADER, newAuthHeader)
152+
.putHeader(X_AMZ_DATE_HEADER, newXAmzDate)
153+
.putHeader(X_AMZ_SECURITY_TOKEN_HEADER, newXAmzSecurityToken)
154+
.build())
155+
.build();
156+
157+
when(this.credentialsProvider.resolveCredentials()).thenReturn(this.credentials);
158+
doReturn(newSignedRequest).when(this.signer).sign(any(Consumer.class));
159+
160+
exporter.export(List.of());
161+
162+
Map<String, String> headers = this.headersCaptor.getValue().get();
163+
164+
assertTrue(headers.containsKey(X_AMZ_DATE_HEADER));
165+
assertTrue(headers.containsKey(AUTHORIZATION_HEADER));
166+
assertTrue(headers.containsKey(X_AMZ_SECURITY_TOKEN_HEADER));
167+
168+
assertEquals(newAuthHeader, headers.get(AUTHORIZATION_HEADER));
169+
assertEquals(newXAmzDate, headers.get(X_AMZ_DATE_HEADER));
170+
assertEquals(newXAmzSecurityToken, headers.get(X_AMZ_SECURITY_TOKEN_HEADER));
171+
}
172+
}
173+
137174
@Test
138175
void testAwsSpanExporterDoesNotAddSigV4HeadersIfFailureToRetrieveCredentials() {
139176

0 commit comments

Comments
 (0)