Skip to content

Commit 757e2ef

Browse files
authored
Remote target (#745)
* Setting SQS remote target to ARN * Adding remote target for the other services * Ran spotless * Adding more tests * Adding more tests * Addressing PR * Fixing contract tests * Fixing PR
1 parent fb25e6d commit 757e2ef

File tree

5 files changed

+333
-24
lines changed

5 files changed

+333
-24
lines changed

appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/awssdk/base/AwsSdkBaseTest.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ protected void doTestS3CreateBucket() throws Exception {
474474

475475
var localService = getApplicationOtelServiceName();
476476
var localOperation = "GET /s3/createbucket/:bucketname";
477-
var target = "create-bucket";
477+
var target = "::s3:::create-bucket";
478478

479479
assertSpanClientAttributes(
480480
traces,
@@ -532,7 +532,7 @@ protected void doTestS3CreateObject() throws Exception {
532532

533533
var localService = getApplicationOtelServiceName();
534534
var localOperation = "GET /s3/createobject/:bucketname/:objectname";
535-
var target = "put-object";
535+
var target = "::s3:::put-object";
536536

537537
assertSpanClientAttributes(
538538
traces,
@@ -589,7 +589,7 @@ protected void doTestS3GetObject() throws Exception {
589589

590590
var localService = getApplicationOtelServiceName();
591591
var localOperation = "GET /s3/getobject/:bucketName/:objectname";
592-
var target = "get-object";
592+
var target = "::s3:::get-object";
593593

594594
assertSpanClientAttributes(
595595
traces,
@@ -646,7 +646,7 @@ protected void doTestS3Error() {
646646

647647
var localService = getApplicationOtelServiceName();
648648
var localOperation = "GET /s3/error";
649-
var target = "error-bucket";
649+
var target = "::s3:::error-bucket";
650650

651651
assertSpanClientAttributes(
652652
traces,
@@ -703,7 +703,7 @@ protected void doTestS3Fault() {
703703

704704
var localService = getApplicationOtelServiceName();
705705
var localOperation = "GET /s3/fault";
706-
var target = "fault-bucket";
706+
var target = "::s3:::fault-bucket";
707707

708708
assertSpanClientAttributes(
709709
traces,
@@ -768,7 +768,7 @@ protected void doTestDynamoDbCreateTable() {
768768

769769
var localService = getApplicationOtelServiceName();
770770
var localOperation = "GET /ddb/createtable/:tablename";
771-
var target = "some-table";
771+
var target = "::dynamodb:::table/some-table";
772772

773773
assertSpanClientAttributes(
774774
traces,
@@ -825,7 +825,7 @@ protected void doTestDynamoDbPutItem() {
825825

826826
var localService = getApplicationOtelServiceName();
827827
var localOperation = "GET /ddb/putitem/:tablename/:partitionkey";
828-
var target = "putitem-table";
828+
var target = "::dynamodb:::table/putitem-table";
829829

830830
assertSpanClientAttributes(
831831
traces,
@@ -882,7 +882,7 @@ protected void doTestDynamoDbError() throws Exception {
882882

883883
var localService = getApplicationOtelServiceName();
884884
var localOperation = "GET /ddb/error";
885-
var target = "nonexistanttable";
885+
var target = "::dynamodb:::table/nonexistanttable";
886886

887887
assertSpanClientAttributes(
888888
traces,
@@ -945,7 +945,7 @@ protected void doTestDynamoDbFault() throws Exception {
945945

946946
var localService = getApplicationOtelServiceName();
947947
var localOperation = "GET /ddb/fault";
948-
var target = "nonexistanttable";
948+
var target = "::dynamodb:::table/nonexistanttable";
949949

950950
assertSpanClientAttributes(
951951
traces,
@@ -1002,7 +1002,7 @@ protected void doTestSQSCreateQueue() throws Exception {
10021002

10031003
var localService = getApplicationOtelServiceName();
10041004
var localOperation = "GET /sqs/createqueue/:queuename";
1005-
var target = "some-queue";
1005+
var target = "::sqs:::some-queue";
10061006

10071007
assertSpanClientAttributes(
10081008
traces,
@@ -1289,7 +1289,7 @@ protected void doTestKinesisPutRecord() throws Exception {
12891289

12901290
var localService = getApplicationOtelServiceName();
12911291
var localOperation = "GET /kinesis/putrecord/:streamname";
1292-
var target = "my-stream";
1292+
var target = "::kinesis:::stream/my-stream";
12931293

12941294
assertSpanClientAttributes(
12951295
traces,
@@ -1346,7 +1346,7 @@ protected void doTestKinesisError() throws Exception {
13461346

13471347
var localService = getApplicationOtelServiceName();
13481348
var localOperation = "GET /kinesis/error";
1349-
var target = "nonexistantstream";
1349+
var target = "::kinesis:::stream/nonexistantstream";
13501350

13511351
assertSpanClientAttributes(
13521352
traces,
@@ -1404,7 +1404,7 @@ protected void doTestKinesisFault() throws Exception {
14041404

14051405
var localService = getApplicationOtelServiceName();
14061406
var localOperation = "GET /kinesis/fault";
1407-
var target = "faultstream";
1407+
var target = "::kinesis:::stream/faultstream";
14081408

14091409
assertSpanClientAttributes(
14101410
traces,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ private AwsAttributeKeys() {}
4646
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/8710
4747

4848
static final AttributeKey<String> AWS_BUCKET_NAME = AttributeKey.stringKey("aws.bucket.name");
49+
static final AttributeKey<String> AWS_QUEUE_URL = AttributeKey.stringKey("aws.queue.url");
4950
static final AttributeKey<String> AWS_QUEUE_NAME = AttributeKey.stringKey("aws.queue.name");
5051
static final AttributeKey<String> AWS_STREAM_NAME = AttributeKey.stringKey("aws.stream.name");
5152
static final AttributeKey<String> AWS_TABLE_NAME = AttributeKey.stringKey("aws.table.name");

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
3838
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_SERVICE;
3939
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_NAME;
40+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_URL;
4041
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_OPERATION;
4142
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
4243
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_TARGET;
@@ -144,13 +145,27 @@ private static void setRemoteTarget(SpanData span, AttributesBuilder builder) {
144145
*/
145146
private static Optional<String> getRemoteTarget(SpanData span) {
146147
if (isKeyPresent(span, AWS_BUCKET_NAME)) {
147-
return Optional.ofNullable(span.getAttributes().get(AWS_BUCKET_NAME));
148-
} else if (isKeyPresent(span, AWS_QUEUE_NAME)) {
149-
return Optional.ofNullable(span.getAttributes().get(AWS_QUEUE_NAME));
150-
} else if (isKeyPresent(span, AWS_STREAM_NAME)) {
151-
return Optional.ofNullable(span.getAttributes().get(AWS_STREAM_NAME));
152-
} else if (isKeyPresent(span, AWS_TABLE_NAME)) {
153-
return Optional.ofNullable(span.getAttributes().get(AWS_TABLE_NAME));
148+
return Optional.ofNullable("::s3:::" + span.getAttributes().get(AWS_BUCKET_NAME));
149+
}
150+
151+
if (isKeyPresent(span, AWS_QUEUE_URL)) {
152+
String arn = SqsUrlParser.getSqsRemoteTarget(span.getAttributes().get(AWS_QUEUE_URL));
153+
154+
if (arn != null) {
155+
return Optional.ofNullable(arn);
156+
}
157+
}
158+
159+
if (isKeyPresent(span, AWS_QUEUE_NAME)) {
160+
return Optional.ofNullable("::sqs:::" + span.getAttributes().get(AWS_QUEUE_NAME));
161+
}
162+
163+
if (isKeyPresent(span, AWS_STREAM_NAME)) {
164+
return Optional.ofNullable("::kinesis:::stream/" + span.getAttributes().get(AWS_STREAM_NAME));
165+
}
166+
167+
if (isKeyPresent(span, AWS_TABLE_NAME)) {
168+
return Optional.ofNullable("::dynamodb:::table/" + span.getAttributes().get(AWS_TABLE_NAME));
154169
}
155170
return Optional.empty();
156171
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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+
public class SqsUrlParser {
19+
private static final char ARN_DELIMETER = ':';
20+
private static final String HTTP_SCHEMA = "http://";
21+
private static final String HTTPS_SCHEMA = "https://";
22+
23+
public static String getSqsRemoteTarget(String sqsUrl) {
24+
sqsUrl = stripSchemaFromUrl(sqsUrl);
25+
26+
if (!isSqsUrl(sqsUrl) && !isLegacySqsUrl(sqsUrl) && !isCustomUrl(sqsUrl)) {
27+
return null;
28+
}
29+
30+
String region = getRegion(sqsUrl);
31+
String accountId = getAccountId(sqsUrl);
32+
String partition = getPartition(sqsUrl);
33+
String queueName = getQueueName(sqsUrl);
34+
35+
StringBuilder remoteTarget = new StringBuilder();
36+
37+
if (region == null && accountId == null && partition == null && queueName == null) {
38+
return null;
39+
}
40+
41+
if (region != null && accountId != null && partition != null && queueName != null) {
42+
remoteTarget.append("arn");
43+
}
44+
45+
remoteTarget
46+
.append(ARN_DELIMETER)
47+
.append(nullToEmpty(partition))
48+
.append(ARN_DELIMETER)
49+
.append("sqs")
50+
.append(ARN_DELIMETER)
51+
.append(nullToEmpty(region))
52+
.append(ARN_DELIMETER)
53+
.append(nullToEmpty(accountId))
54+
.append(ARN_DELIMETER)
55+
.append(queueName);
56+
57+
return remoteTarget.toString();
58+
}
59+
60+
private static String stripSchemaFromUrl(String url) {
61+
return url.replace(HTTP_SCHEMA, "").replace(HTTPS_SCHEMA, "");
62+
}
63+
64+
private static String getRegion(String sqsUrl) {
65+
if (sqsUrl == null) {
66+
return null;
67+
}
68+
69+
if (sqsUrl.startsWith("queue.amazonaws.com/")) {
70+
return "us-east-1";
71+
} else if (isSqsUrl(sqsUrl)) {
72+
return getRegionFromSqsUrl(sqsUrl);
73+
} else if (isLegacySqsUrl(sqsUrl)) {
74+
return getRegionFromLegacySqsUrl(sqsUrl);
75+
} else {
76+
return null;
77+
}
78+
}
79+
80+
private static boolean isSqsUrl(String sqsUrl) {
81+
String[] split = sqsUrl.split("/");
82+
83+
return split.length == 3
84+
&& split[0].startsWith("sqs.")
85+
&& split[0].endsWith(".amazonaws.com")
86+
&& isAccountId(split[1])
87+
&& isValidQueueName(split[2]);
88+
}
89+
90+
private static boolean isLegacySqsUrl(String sqsUrl) {
91+
String[] split = sqsUrl.split("/");
92+
93+
return split.length == 3
94+
&& split[0].endsWith(".queue.amazonaws.com")
95+
&& isAccountId(split[1])
96+
&& isValidQueueName(split[2]);
97+
}
98+
99+
private static boolean isCustomUrl(String sqsUrl) {
100+
String[] split = sqsUrl.split("/");
101+
return split.length == 3 && isAccountId(split[1]) && isValidQueueName(split[2]);
102+
}
103+
104+
private static boolean isValidQueueName(String input) {
105+
if (input.length() == 0 || input.length() > 80) {
106+
return false;
107+
}
108+
109+
for (Character c : input.toCharArray()) {
110+
if (c != '_' && c != '-' && !Character.isAlphabetic(c) && !Character.isDigit(c)) {
111+
return false;
112+
}
113+
}
114+
115+
return true;
116+
}
117+
118+
private static boolean isAccountId(String input) {
119+
if (input.length() != 12) {
120+
return false;
121+
}
122+
123+
try {
124+
Long.valueOf(input);
125+
} catch (Exception e) {
126+
return false;
127+
}
128+
129+
return true;
130+
}
131+
132+
private static String getRegionFromSqsUrl(String sqsUrl) {
133+
String[] split = sqsUrl.split("\\.");
134+
135+
if (split.length >= 2) {
136+
return split[1];
137+
}
138+
139+
return null;
140+
}
141+
142+
private static String getRegionFromLegacySqsUrl(String sqsUrl) {
143+
String[] split = sqsUrl.split("\\.");
144+
return split[0];
145+
}
146+
147+
private static String getAccountId(String sqsUrl) {
148+
if (sqsUrl == null) {
149+
return null;
150+
}
151+
152+
String[] split = sqsUrl.split("/");
153+
if (split.length >= 2) {
154+
return split[1];
155+
}
156+
157+
return null;
158+
}
159+
160+
private static String getPartition(String sqsUrl) {
161+
String region = getRegion(sqsUrl);
162+
163+
if (region == null) {
164+
return null;
165+
}
166+
167+
if (region.startsWith("us-gov-")) {
168+
return "aws-us-gov";
169+
} else if (region.startsWith("cn-")) {
170+
return "aws-cn";
171+
} else {
172+
return "aws";
173+
}
174+
}
175+
176+
private static String getQueueName(String sqsUrl) {
177+
String[] split = sqsUrl.split("/");
178+
179+
if (split.length >= 3) {
180+
return split[2];
181+
}
182+
183+
return null;
184+
}
185+
186+
private static String nullToEmpty(String input) {
187+
return input == null ? "" : input;
188+
}
189+
}

0 commit comments

Comments
 (0)