Use reflection to get request metadata instead of instrumentation.
MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsClientInstrumentation.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsClientInstrumentation.java
@@ -10,9 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.declaresField;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
-import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.handlers.RequestHandler2;
-import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
@@ -52,9 +50,7 @@ public class AwsClientInstrumentation implements TypeInstrumentation {
}
}
if (!hasAgentHandler) {
- handlers.add(
- new TracingRequestHandler(
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class)));
+ handlers.add(new TracingRequestHandler());
}
}
}

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsHttpClientInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
+import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
-import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkClientTracer.java
@@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
import com.amazonaws.AmazonWebServiceResponse;
import com.amazonaws.Request;
import com.amazonaws.Response;
+import com.amazonaws.handlers.HandlerContextKey;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
@@ -20,6 +21,11 @@ import java.util.concurrent.ConcurrentHashMap;
public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>, Response<?>> {
+ // Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context
+ // safely.
+ public static final HandlerContextKey<ContextScopePair> CONTEXT_SCOPE_PAIR_CONTEXT_KEY =
+ new HandlerContextKey<>(AwsSdkClientTracer.class.getName() + ".ContextScopePair");
+
private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES =
Config.get()
.getBooleanProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", false);
@@ -61,8 +67,7 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
return qualifiedOperation(awsServiceName, awsOperation);
}
- public Context startSpan(
- SpanKind kind, Context parentContext, Request<?> request, RequestMeta requestMeta) {
+ public Context startSpan(SpanKind kind, Context parentContext, Request<?> request) {
Context context = super.startSpan(kind, parentContext, request, request, -1);
Span span = Span.fromContext(context);
@@ -74,12 +79,26 @@ public class AwsSdkClientTracer extends HttpClientTracer<Request<?>, Request<?>,
span.setAttribute("aws.operation", extractOperationName(request));
span.setAttribute("aws.endpoint", request.getEndpoint().toString());
- if (requestMeta != null) {
- span.setAttribute("aws.bucket.name", requestMeta.getBucketName());
- span.setAttribute("aws.queue.url", requestMeta.getQueueUrl());
- span.setAttribute("aws.queue.name", requestMeta.getQueueName());
- span.setAttribute("aws.stream.name", requestMeta.getStreamName());
- span.setAttribute("aws.table.name", requestMeta.getTableName());
+ Object originalRequest = request.getOriginalRequest();
+ String bucketName = RequestAccess.getBucketName(originalRequest);
+ if (bucketName != null) {
+ span.setAttribute("aws.bucket.name", bucketName);
+ }
+ String queueUrl = RequestAccess.getQueueUrl(originalRequest);
+ if (queueUrl != null) {
+ span.setAttribute("aws.queue.url", queueUrl);
+ }
+ String queueName = RequestAccess.getQueueName(originalRequest);
+ if (queueName != null) {
+ span.setAttribute("aws.queue.name", queueName);
+ }
+ String streamName = RequestAccess.getStreamName(originalRequest);
+ if (streamName != null) {
+ span.setAttribute("aws.stream.name", streamName);
+ }
+ String tableName = RequestAccess.getTableName(originalRequest);
+ if (tableName != null) {
+ span.setAttribute("aws.table.name", tableName);
}
}
return context;

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkInstrumentationModule.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSdkInstrumentationModule.java
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
import static java.util.Arrays.asList;
-import static java.util.Collections.singletonMap;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
-import java.util.Map;
@AutoService(InstrumentationModule.class)
public class AwsSdkInstrumentationModule extends InstrumentationModule {
@@ -30,14 +28,6 @@ public class AwsSdkInstrumentationModule extends InstrumentationModule {
return asList(
new AwsClientInstrumentation(),
new AwsHttpClientInstrumentation(),
- new RequestExecutorInstrumentation(),
- new RequestInstrumentation());
- }
-
- @Override
- public Map<String, String> contextStore() {
- return singletonMap(
- "com.amazonaws.AmazonWebServiceRequest",
- "io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta");
+ new RequestExecutorInstrumentation());
}
}

ADD
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestAccess.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+final class RequestAccess {
+
+ private static final ClassValue<RequestAccess> REQUEST_ACCESSORS =
+ new ClassValue<RequestAccess>() {
+ @Override
+ protected RequestAccess computeValue(Class<?> type) {
+ return new RequestAccess(type);
+ }
+ };
+
+ @Nullable
+ static String getBucketName(Object request) {
+ RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
+ return invokeOrNull(access.getBucketName, request);
+ }
+
+ @Nullable
+ static String getQueueUrl(Object request) {
+ RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
+ return invokeOrNull(access.getQueueUrl, request);
+ }
+
+ @Nullable
+ static String getQueueName(Object request) {
+ RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
+ return invokeOrNull(access.getQueueName, request);
+ }
+
+ @Nullable
+ static String getStreamName(Object request) {
+ RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
+ return invokeOrNull(access.getStreamName, request);
+ }
+
+ @Nullable
+ static String getTableName(Object request) {
+ RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
+ return invokeOrNull(access.getTableName, request);
+ }
+
+ @Nullable
+ private static String invokeOrNull(@Nullable MethodHandle method, Object obj) {
+ if (method == null) {
+ return null;
+ }
+ try {
+ return (String) method.invoke(obj);
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+
+ @Nullable private final MethodHandle getBucketName;
+ @Nullable private final MethodHandle getQueueUrl;
+ @Nullable private final MethodHandle getQueueName;
+ @Nullable private final MethodHandle getStreamName;
+ @Nullable private final MethodHandle getTableName;
+
+ private RequestAccess(Class<?> clz) {
+ getBucketName = findAccessorOrNull(clz, "getBucketName");
+ getQueueUrl = findAccessorOrNull(clz, "getQueueUrl");
+ getQueueName = findAccessorOrNull(clz, "getQueueName");
+ getStreamName = findAccessorOrNull(clz, "getStreamName");
+ getTableName = findAccessorOrNull(clz, "getTableName");
+ }
+
+ @Nullable
+ private static MethodHandle findAccessorOrNull(Class<?> clz, String methodName) {
+ try {
+ return MethodHandles.publicLookup()
+ .findVirtual(clz, methodName, MethodType.methodType(String.class));
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+}

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestExecutorInstrumentation.java
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
+import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
-import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;

DELETE
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestInstrumentation.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
-
-import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
-import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.ClassLoaderMatcher.hasClassesNamed;
-import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
-import static net.bytebuddy.matcher.ElementMatchers.named;
-import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
-
-import com.amazonaws.AmazonWebServiceRequest;
-import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
-import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
-import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
-import java.util.HashMap;
-import java.util.Map;
-import net.bytebuddy.asm.Advice;
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.description.type.TypeDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-
-public class RequestInstrumentation implements TypeInstrumentation {
-
- @Override
- public ElementMatcher<ClassLoader> classLoaderOptimization() {
- return hasClassesNamed("com.amazonaws.AmazonWebServiceRequest");
- }
-
- @Override
- public ElementMatcher<TypeDescription> typeMatcher() {
- return nameStartsWith("com.amazonaws.services.")
- .and(extendsClass(named("com.amazonaws.AmazonWebServiceRequest")));
- }
-
- @Override
- public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
- Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
- transformers.put(
- named("setBucketName").and(takesArgument(0, String.class)),
- RequestInstrumentation.class.getName() + "$BucketNameAdvice");
- transformers.put(
- named("setQueueUrl").and(takesArgument(0, String.class)),
- RequestInstrumentation.class.getName() + "$QueueUrlAdvice");
- transformers.put(
- named("setQueueName").and(takesArgument(0, String.class)),
- RequestInstrumentation.class.getName() + "$QueueNameAdvice");
- transformers.put(
- named("setStreamName").and(takesArgument(0, String.class)),
- RequestInstrumentation.class.getName() + "$StreamNameAdvice");
- transformers.put(
- named("setTableName").and(takesArgument(0, String.class)),
- RequestInstrumentation.class.getName() + "$TableNameAdvice");
- return transformers;
- }
-
- public static class BucketNameAdvice {
- @Advice.OnMethodEnter(suppress = Throwable.class)
- public static void methodEnter(
- @Advice.Argument(0) String value, @Advice.This AmazonWebServiceRequest request) {
- ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore =
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class);
- RequestMeta requestMeta = contextStore.get(request);
- if (requestMeta == null) {
- requestMeta = new RequestMeta();
- contextStore.put(request, requestMeta);
- }
- requestMeta.setBucketName(value);
- }
- }
-
- public static class QueueUrlAdvice {
- @Advice.OnMethodEnter(suppress = Throwable.class)
- public static void methodEnter(
- @Advice.Argument(0) String value, @Advice.This AmazonWebServiceRequest request) {
- ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore =
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class);
- RequestMeta requestMeta = contextStore.get(request);
- if (requestMeta == null) {
- requestMeta = new RequestMeta();
- contextStore.put(request, requestMeta);
- }
- requestMeta.setQueueUrl(value);
- }
- }
-
- public static class QueueNameAdvice {
- @Advice.OnMethodEnter(suppress = Throwable.class)
- public static void methodEnter(
- @Advice.Argument(0) String value, @Advice.This AmazonWebServiceRequest request) {
- ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore =
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class);
- RequestMeta requestMeta = contextStore.get(request);
- if (requestMeta == null) {
- requestMeta = new RequestMeta();
- contextStore.put(request, requestMeta);
- }
- requestMeta.setQueueName(value);
- }
- }
-
- public static class StreamNameAdvice {
- @Advice.OnMethodEnter(suppress = Throwable.class)
- public static void methodEnter(
- @Advice.Argument(0) String value, @Advice.This AmazonWebServiceRequest request) {
- ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore =
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class);
- RequestMeta requestMeta = contextStore.get(request);
- if (requestMeta == null) {
- requestMeta = new RequestMeta();
- contextStore.put(request, requestMeta);
- }
- requestMeta.setStreamName(value);
- }
- }
-
- public static class TableNameAdvice {
- @Advice.OnMethodEnter(suppress = Throwable.class)
- public static void methodEnter(
- @Advice.Argument(0) String value, @Advice.This AmazonWebServiceRequest request) {
- ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore =
- InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class);
- RequestMeta requestMeta = contextStore.get(request);
- if (requestMeta == null) {
- requestMeta = new RequestMeta();
- contextStore.put(request, requestMeta);
- }
- requestMeta.setTableName(value);
- }
- }
-}

DELETE
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/RequestMeta.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
-
-import com.amazonaws.handlers.HandlerContextKey;
-import java.util.Objects;
-
-public class RequestMeta {
- // Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context
- // safely.
- public static final HandlerContextKey<ContextScopePair> CONTEXT_SCOPE_PAIR_CONTEXT_KEY =
- new HandlerContextKey<>(RequestMeta.class.getName() + ".ContextScopePair");
-
- private String bucketName;
- private String queueUrl;
- private String queueName;
- private String streamName;
- private String tableName;
-
- public String getBucketName() {
- return bucketName;
- }
-
- public void setBucketName(String bucketName) {
- this.bucketName = bucketName;
- }
-
- public String getQueueUrl() {
- return queueUrl;
- }
-
- public void setQueueUrl(String queueUrl) {
- this.queueUrl = queueUrl;
- }
-
- public String getQueueName() {
- return queueName;
- }
-
- public void setQueueName(String queueName) {
- this.queueName = queueName;
- }
-
- public String getStreamName() {
- return streamName;
- }
-
- public void setStreamName(String streamName) {
- this.streamName = streamName;
- }
-
- public String getTableName() {
- return tableName;
- }
-
- public void setTableName(String tableName) {
- this.tableName = tableName;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof RequestMeta)) {
- return false;
- }
- RequestMeta other = (RequestMeta) obj;
- return Objects.equals(bucketName, other.bucketName)
- && Objects.equals(queueUrl, other.queueUrl)
- && Objects.equals(queueName, other.queueName)
- && Objects.equals(streamName, other.streamName)
- && Objects.equals(tableName, other.tableName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(bucketName, queueUrl, queueName, streamName, tableName);
- }
-}

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/TracingRequestHandler.java
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
+import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.AwsSdkClientTracer.tracer;
-import static io.opentelemetry.javaagent.instrumentation.awssdk.v1_11.RequestMeta.CONTEXT_SCOPE_PAIR_CONTEXT_KEY;
import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.Request;
@@ -15,30 +15,22 @@ import com.amazonaws.handlers.RequestHandler2;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
-import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import java.util.List;
/** Tracing Request Handler. */
public class TracingRequestHandler extends RequestHandler2 {
- private final ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore;
-
- public TracingRequestHandler(ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore) {
- this.contextStore = contextStore;
- }
-
@Override
public void beforeRequest(Request<?> request) {
AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
SpanKind kind = (isSqsProducer(originalRequest) ? SpanKind.PRODUCER : SpanKind.CLIENT);
- RequestMeta requestMeta = contextStore.get(originalRequest);
Context parentContext = Context.current();
if (!tracer().shouldStartSpan(parentContext)) {
return;
}
- Context context = tracer().startSpan(kind, parentContext, request, requestMeta);
+ Context context = tracer().startSpan(kind, parentContext, request);
Scope scope = context.makeCurrent();
request.addHandlerContext(CONTEXT_SCOPE_PAIR_CONTEXT_KEY, new ContextScopePair(context, scope));
}
@@ -89,9 +81,7 @@ public class TracingRequestHandler extends RequestHandler2 {
private void createConsumerSpan(Object message, Request<?> request, Response<?> response) {
Context parentContext =
SqsParentContext.ofSystemAttributes(SqsMessageAccess.getAttributes(message));
- AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
- RequestMeta requestMeta = contextStore.get(originalRequest);
- Context context = tracer().startSpan(SpanKind.CONSUMER, parentContext, request, requestMeta);
+ Context context = tracer().startSpan(SpanKind.CONSUMER, parentContext, request);
tracer().end(context, response);
}

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/Aws1ClientTest.groovy
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/Aws1ClientTest.groovy
@@ -258,6 +258,7 @@ class Aws1ClientTest extends AgentInstrumentationSpecification {
"aws.endpoint" "https://s3.amazonaws.com"
"aws.operation" "HeadBucket"
"aws.agent" "java-aws-sdk"
+ "aws.bucket.name" "someBucket"
}
}
}

Use reflection to get request metadata instead of instrumentation. (#2508)