From 4cc213cd0bad52610c2c46fb93dc1169c1e52492 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Wed, 26 Jan 2022 02:27:35 +0000 Subject: [PATCH] Support AWS SDK v1 request object subclasses. --- .../v1_11/AwsSdkInstrumenterFactory.java | 3 ++- .../v1_11/AwsSdkRpcAttributesExtractor.java | 8 ++++++- .../awssdk/v1_11/AwsSdkSpanNameExtractor.java | 24 ++++++++++--------- .../v1_11/AbstractAws1ClientTest.groovy | 7 +++++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkInstrumenterFactory.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkInstrumenterFactory.java index 2a2d742dc1ff..1f2903b39292 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkInstrumenterFactory.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkInstrumenterFactory.java @@ -38,7 +38,8 @@ final class AwsSdkInstrumenterFactory { rpcAttributesExtractor, netAttributesExtractor, experimentalAttributesExtractor); - private static final AwsSdkSpanNameExtractor spanName = new AwsSdkSpanNameExtractor(); + private static final AwsSdkSpanNameExtractor spanName = + new AwsSdkSpanNameExtractor(rpcAttributesExtractor); static Instrumenter, Response> requestInstrumenter( OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) { diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkRpcAttributesExtractor.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkRpcAttributesExtractor.java index 929ce6885a23..f6a12cb46d40 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkRpcAttributesExtractor.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkRpcAttributesExtractor.java @@ -16,7 +16,13 @@ final class AwsSdkRpcAttributesExtractor extends RpcAttributesExtractor type) { String ret = type.getSimpleName(); - ret = ret.substring(0, ret.length() - 7); // remove 'Request' + if (!ret.endsWith("Request")) { + // Best effort check one parent to support implicit subclasses + ret = type.getSuperclass().getSimpleName(); + } + if (ret.endsWith("Request")) { + ret = ret.substring(0, ret.length() - 7); // remove 'Request' + } return ret; } }; diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkSpanNameExtractor.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkSpanNameExtractor.java index 7685a2fa6c8b..962371da149b 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkSpanNameExtractor.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkSpanNameExtractor.java @@ -10,23 +10,25 @@ import java.util.concurrent.ConcurrentHashMap; class AwsSdkSpanNameExtractor implements SpanNameExtractor> { + + private final AwsSdkRpcAttributesExtractor rpcAttributes; private final NamesCache namesCache = new NamesCache(); + AwsSdkSpanNameExtractor(AwsSdkRpcAttributesExtractor rpcAttributes) { + this.rpcAttributes = rpcAttributes; + } + @Override public String extract(Request request) { - String awsServiceName = request.getServiceName(); - Class awsOperation = request.getOriginalRequest().getClass(); - return qualifiedOperation(awsServiceName, awsOperation); + return qualifiedOperation( + rpcAttributes.service(request), + rpcAttributes.method(request), + request.getOriginalRequest().getClass()); } - private String qualifiedOperation(String service, Class operation) { - ConcurrentHashMap cache = namesCache.get(operation); - return cache.computeIfAbsent( - service, - s -> - s.replace("Amazon", "").trim() - + '.' - + operation.getSimpleName().replace("Request", "")); + private String qualifiedOperation(String service, String operation, Class requestClass) { + ConcurrentHashMap cache = namesCache.get(requestClass); + return cache.computeIfAbsent(service, s -> s.replace("Amazon", "").trim() + '.' + operation); } static final class NamesCache extends ClassValue> { diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy index e674579d5692..4efad86eec78 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy @@ -94,7 +94,7 @@ abstract class AbstractAws1ClientTest extends InstrumentationSpecification { response != null client.requestHandler2s != null - client.requestHandler2s.find{it.getClass().getSimpleName() == "TracingRequestHandler"} != null + client.requestHandler2s.find { it.getClass().getSimpleName() == "TracingRequestHandler" } != null assertTraces(1) { trace(0, 1) { @@ -133,6 +133,11 @@ abstract class AbstractAws1ClientTest extends InstrumentationSpecification { "S3" | "GetObject" | "GET" | "/someBucket/someKey" | AmazonS3ClientBuilder.standard().withPathStyleAccessEnabled(true) | { c -> c.getObject("someBucket", "someKey") } | ["aws.bucket.name": "someBucket"] | "" "DynamoDBv2" | "CreateTable" | "POST" | "/" | AmazonDynamoDBClientBuilder.standard() | { c -> c.createTable(new CreateTableRequest("sometable", null)) } | ["aws.table.name": "sometable"] | "" "Kinesis" | "DeleteStream" | "POST" | "/" | AmazonKinesisClientBuilder.standard() | { c -> c.deleteStream(new DeleteStreamRequest().withStreamName("somestream")) } | ["aws.stream.name": "somestream"] | "" + // Some users may implicitly subclass the request object to mimic a fluent style + "Kinesis" | "DeleteStream" | "POST" | "/" | AmazonKinesisClientBuilder.standard() | { c -> + c.deleteStream(new DeleteStreamRequest() { + { withStreamName("somestream") } + }) } | ["aws.stream.name": "somestream"] | "" "EC2" | "AllocateAddress" | "POST" | "/" | AmazonEC2ClientBuilder.standard() | { c -> c.allocateAddress() } | [:] | """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE