Skip to content

Commit

Permalink
Remote target (#745)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
atshaw43 authored Feb 13, 2024
1 parent fb25e6d commit 757e2ef
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ protected void doTestS3CreateBucket() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /s3/createbucket/:bucketname";
var target = "create-bucket";
var target = "::s3:::create-bucket";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -532,7 +532,7 @@ protected void doTestS3CreateObject() throws Exception {

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

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -589,7 +589,7 @@ protected void doTestS3GetObject() throws Exception {

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

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -646,7 +646,7 @@ protected void doTestS3Error() {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /s3/error";
var target = "error-bucket";
var target = "::s3:::error-bucket";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -703,7 +703,7 @@ protected void doTestS3Fault() {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /s3/fault";
var target = "fault-bucket";
var target = "::s3:::fault-bucket";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -768,7 +768,7 @@ protected void doTestDynamoDbCreateTable() {

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

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -825,7 +825,7 @@ protected void doTestDynamoDbPutItem() {

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

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -882,7 +882,7 @@ protected void doTestDynamoDbError() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /ddb/error";
var target = "nonexistanttable";
var target = "::dynamodb:::table/nonexistanttable";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -945,7 +945,7 @@ protected void doTestDynamoDbFault() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /ddb/fault";
var target = "nonexistanttable";
var target = "::dynamodb:::table/nonexistanttable";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -1002,7 +1002,7 @@ protected void doTestSQSCreateQueue() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /sqs/createqueue/:queuename";
var target = "some-queue";
var target = "::sqs:::some-queue";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -1289,7 +1289,7 @@ protected void doTestKinesisPutRecord() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /kinesis/putrecord/:streamname";
var target = "my-stream";
var target = "::kinesis:::stream/my-stream";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -1346,7 +1346,7 @@ protected void doTestKinesisError() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /kinesis/error";
var target = "nonexistantstream";
var target = "::kinesis:::stream/nonexistantstream";

assertSpanClientAttributes(
traces,
Expand Down Expand Up @@ -1404,7 +1404,7 @@ protected void doTestKinesisFault() throws Exception {

var localService = getApplicationOtelServiceName();
var localOperation = "GET /kinesis/fault";
var target = "faultstream";
var target = "::kinesis:::stream/faultstream";

assertSpanClientAttributes(
traces,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ private AwsAttributeKeys() {}
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/8710

static final AttributeKey<String> AWS_BUCKET_NAME = AttributeKey.stringKey("aws.bucket.name");
static final AttributeKey<String> AWS_QUEUE_URL = AttributeKey.stringKey("aws.queue.url");
static final AttributeKey<String> AWS_QUEUE_NAME = AttributeKey.stringKey("aws.queue.name");
static final AttributeKey<String> AWS_STREAM_NAME = AttributeKey.stringKey("aws.stream.name");
static final AttributeKey<String> AWS_TABLE_NAME = AttributeKey.stringKey("aws.table.name");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_URL;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_OPERATION;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_TARGET;
Expand Down Expand Up @@ -144,13 +145,27 @@ private static void setRemoteTarget(SpanData span, AttributesBuilder builder) {
*/
private static Optional<String> getRemoteTarget(SpanData span) {
if (isKeyPresent(span, AWS_BUCKET_NAME)) {
return Optional.ofNullable(span.getAttributes().get(AWS_BUCKET_NAME));
} else if (isKeyPresent(span, AWS_QUEUE_NAME)) {
return Optional.ofNullable(span.getAttributes().get(AWS_QUEUE_NAME));
} else if (isKeyPresent(span, AWS_STREAM_NAME)) {
return Optional.ofNullable(span.getAttributes().get(AWS_STREAM_NAME));
} else if (isKeyPresent(span, AWS_TABLE_NAME)) {
return Optional.ofNullable(span.getAttributes().get(AWS_TABLE_NAME));
return Optional.ofNullable("::s3:::" + span.getAttributes().get(AWS_BUCKET_NAME));
}

if (isKeyPresent(span, AWS_QUEUE_URL)) {
String arn = SqsUrlParser.getSqsRemoteTarget(span.getAttributes().get(AWS_QUEUE_URL));

if (arn != null) {
return Optional.ofNullable(arn);
}
}

if (isKeyPresent(span, AWS_QUEUE_NAME)) {
return Optional.ofNullable("::sqs:::" + span.getAttributes().get(AWS_QUEUE_NAME));
}

if (isKeyPresent(span, AWS_STREAM_NAME)) {
return Optional.ofNullable("::kinesis:::stream/" + span.getAttributes().get(AWS_STREAM_NAME));
}

if (isKeyPresent(span, AWS_TABLE_NAME)) {
return Optional.ofNullable("::dynamodb:::table/" + span.getAttributes().get(AWS_TABLE_NAME));
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* 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;

public class SqsUrlParser {
private static final char ARN_DELIMETER = ':';
private static final String HTTP_SCHEMA = "http://";
private static final String HTTPS_SCHEMA = "https://";

public static String getSqsRemoteTarget(String sqsUrl) {
sqsUrl = stripSchemaFromUrl(sqsUrl);

if (!isSqsUrl(sqsUrl) && !isLegacySqsUrl(sqsUrl) && !isCustomUrl(sqsUrl)) {
return null;
}

String region = getRegion(sqsUrl);
String accountId = getAccountId(sqsUrl);
String partition = getPartition(sqsUrl);
String queueName = getQueueName(sqsUrl);

StringBuilder remoteTarget = new StringBuilder();

if (region == null && accountId == null && partition == null && queueName == null) {
return null;
}

if (region != null && accountId != null && partition != null && queueName != null) {
remoteTarget.append("arn");
}

remoteTarget
.append(ARN_DELIMETER)
.append(nullToEmpty(partition))
.append(ARN_DELIMETER)
.append("sqs")
.append(ARN_DELIMETER)
.append(nullToEmpty(region))
.append(ARN_DELIMETER)
.append(nullToEmpty(accountId))
.append(ARN_DELIMETER)
.append(queueName);

return remoteTarget.toString();
}

private static String stripSchemaFromUrl(String url) {
return url.replace(HTTP_SCHEMA, "").replace(HTTPS_SCHEMA, "");
}

private static String getRegion(String sqsUrl) {
if (sqsUrl == null) {
return null;
}

if (sqsUrl.startsWith("queue.amazonaws.com/")) {
return "us-east-1";
} else if (isSqsUrl(sqsUrl)) {
return getRegionFromSqsUrl(sqsUrl);
} else if (isLegacySqsUrl(sqsUrl)) {
return getRegionFromLegacySqsUrl(sqsUrl);
} else {
return null;
}
}

private static boolean isSqsUrl(String sqsUrl) {
String[] split = sqsUrl.split("/");

return split.length == 3
&& split[0].startsWith("sqs.")
&& split[0].endsWith(".amazonaws.com")
&& isAccountId(split[1])
&& isValidQueueName(split[2]);
}

private static boolean isLegacySqsUrl(String sqsUrl) {
String[] split = sqsUrl.split("/");

return split.length == 3
&& split[0].endsWith(".queue.amazonaws.com")
&& isAccountId(split[1])
&& isValidQueueName(split[2]);
}

private static boolean isCustomUrl(String sqsUrl) {
String[] split = sqsUrl.split("/");
return split.length == 3 && isAccountId(split[1]) && isValidQueueName(split[2]);
}

private static boolean isValidQueueName(String input) {
if (input.length() == 0 || input.length() > 80) {
return false;
}

for (Character c : input.toCharArray()) {
if (c != '_' && c != '-' && !Character.isAlphabetic(c) && !Character.isDigit(c)) {
return false;
}
}

return true;
}

private static boolean isAccountId(String input) {
if (input.length() != 12) {
return false;
}

try {
Long.valueOf(input);
} catch (Exception e) {
return false;
}

return true;
}

private static String getRegionFromSqsUrl(String sqsUrl) {
String[] split = sqsUrl.split("\\.");

if (split.length >= 2) {
return split[1];
}

return null;
}

private static String getRegionFromLegacySqsUrl(String sqsUrl) {
String[] split = sqsUrl.split("\\.");
return split[0];
}

private static String getAccountId(String sqsUrl) {
if (sqsUrl == null) {
return null;
}

String[] split = sqsUrl.split("/");
if (split.length >= 2) {
return split[1];
}

return null;
}

private static String getPartition(String sqsUrl) {
String region = getRegion(sqsUrl);

if (region == null) {
return null;
}

if (region.startsWith("us-gov-")) {
return "aws-us-gov";
} else if (region.startsWith("cn-")) {
return "aws-cn";
} else {
return "aws";
}
}

private static String getQueueName(String sqsUrl) {
String[] split = sqsUrl.split("/");

if (split.length >= 3) {
return split[2];
}

return null;
}

private static String nullToEmpty(String input) {
return input == null ? "" : input;
}
}
Loading

0 comments on commit 757e2ef

Please sign in to comment.