Migrate AWS SDK v2 to new library API pattern.
MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java
package io.opentelemetry.javaagent.instrumentation.awssdk.v2_2;
-import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTracing;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Optional;
@@ -33,7 +35,7 @@ import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SdkHttpResponse;
/**
- * {@link ExecutionInterceptor} that delegates to {@link AwsSdk}, augmenting {@link
+ * {@link ExecutionInterceptor} that delegates to {@link AwsSdkTracing}, augmenting {@link
* #beforeTransmission(BeforeTransmission, ExecutionAttributes)} to make sure the span is set to the
* current context to allow downstream instrumentation like Netty to pick it up.
*/
@@ -42,7 +44,14 @@ public class TracingExecutionInterceptor implements ExecutionInterceptor {
private final ExecutionInterceptor delegate;
public TracingExecutionInterceptor() {
- delegate = AwsSdk.newInterceptor();
+ delegate =
+ AwsSdkTracing.newBuilder(GlobalOpenTelemetry.get())
+ .setCaptureExperimentalSpanAttributes(
+ Config.get()
+ .getBooleanProperty(
+ "otel.instrumentation.aws-sdk.experimental-span-attributes", false))
+ .build()
+ .newExecutionInterceptor();
}
@Override

DELETE
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.instrumentation.awssdk.v2_2;
-
-import static io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor.CONTEXT_ATTRIBUTE;
-
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.api.trace.Tracer;
-import io.opentelemetry.context.Context;
-import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
-import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
-
-/**
- * Entrypoint to OpenTelemetry instrumentation of the AWS SDK. Register the {@link
- * ExecutionInterceptor} returned by {@link #newInterceptor()} with an SDK client to have all
- * requests traced.
- *
- * <pre>{@code
- * DynamoDbClient dynamoDb = DynamoDbClient.builder()
- * .overrideConfiguration(ClientOverrideConfiguration.builder()
- * .addExecutionInterceptor(AwsSdk.newInterceptor())
- * .build())
- * .build();
- * }</pre>
- */
-public class AwsSdk {
-
- private static final Tracer tracer =
- GlobalOpenTelemetry.getTracer(AwsSdkHttpClientTracer.tracer().getInstrumentationName());
-
- /** Returns the {@link Tracer} used to instrument the AWS SDK. */
- public static Tracer tracer() {
- return tracer;
- }
-
- /**
- * Returns an {@link ExecutionInterceptor} that can be used with an {@link
- * software.amazon.awssdk.http.SdkHttpClient} to trace SDK requests.
- */
- public static ExecutionInterceptor newInterceptor() {
- return new TracingExecutionInterceptor();
- }
-
- /**
- * Returns the {@link Context} stored in the {@link ExecutionAttributes}, or {@code null} if there
- * is no operation set.
- */
- public static Context getContext(ExecutionAttributes attributes) {
- return attributes.getAttribute(CONTEXT_ATTRIBUTE);
- }
-}

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkHttpClientTracer.java
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkHttpClientTracer.java
@@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2;
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
+import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapSetter;
@@ -22,10 +23,8 @@ import software.amazon.awssdk.http.SdkHttpResponse;
final class AwsSdkHttpClientTracer
extends HttpClientTracer<SdkHttpRequest, SdkHttpRequest.Builder, SdkHttpResponse> {
- private static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer();
-
- static AwsSdkHttpClientTracer tracer() {
- return TRACER;
+ AwsSdkHttpClientTracer(OpenTelemetry openTelemetry) {
+ super(openTelemetry);
}
public Context startSpan(Context parentContext, ExecutionAttributes attributes) {

ADD
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkTracing.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awssdk.v2_2;
+
+import io.opentelemetry.api.OpenTelemetry;
+import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
+import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
+
+/**
+ * Entrypoint to OpenTelemetry instrumentation of the AWS SDK. Register the {@link
+ * ExecutionInterceptor} returned by {@link #newExecutionInterceptor()} with an SDK client to have
+ * all requests traced.
+ *
+ * <pre>{@code
+ * DynamoDbClient dynamoDb = DynamoDbClient.builder()
+ * .overrideConfiguration(ClientOverrideConfiguration.builder()
+ * .addExecutionInterceptor(AwsSdkTracing.create(openTelemetry).newExecutionInterceptor())
+ * .build())
+ * .build();
+ * }</pre>
+ */
+public class AwsSdkTracing {
+
+ /** Returns a new {@link AwsSdkTracing} configured with the given {@link OpenTelemetry}. */
+ public static AwsSdkTracing create(OpenTelemetry openTelemetry) {
+ return newBuilder(openTelemetry).build();
+ }
+
+ /** Returns a new {@link AwsSdkTracingBuilder} configured with the given {@link OpenTelemetry}. */
+ public static AwsSdkTracingBuilder newBuilder(OpenTelemetry openTelemetry) {
+ return new AwsSdkTracingBuilder(openTelemetry);
+ }
+
+ private final AwsSdkHttpClientTracer tracer;
+ private final boolean captureExperimentalSpanAttributes;
+
+ AwsSdkTracing(OpenTelemetry openTelemetry, boolean captureExperimentalSpanAttributes) {
+ this.tracer = new AwsSdkHttpClientTracer(openTelemetry);
+ this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
+ }
+
+ /**
+ * Returns a new {@link ExecutionInterceptor} that can be used with methods like {@link
+ * ClientOverrideConfiguration.Builder#addExecutionInterceptor(ExecutionInterceptor)}.
+ */
+ public ExecutionInterceptor newExecutionInterceptor() {
+ return new TracingExecutionInterceptor(tracer, captureExperimentalSpanAttributes);
+ }
+}

ADD
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkTracingBuilder.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awssdk.v2_2;
+
+import io.opentelemetry.api.OpenTelemetry;
+
+/** A builder of {@link AwsSdkTracing}. */
+public final class AwsSdkTracingBuilder {
+
+ private final OpenTelemetry openTelemetry;
+
+ private boolean captureExperimentalSpanAttributes;
+
+ AwsSdkTracingBuilder(OpenTelemetry openTelemetry) {
+ this.openTelemetry = openTelemetry;
+ }
+
+ /**
+ * Sets whether experimental attributes should be set to spans. These attributes may be changed or
+ * removed in the future, so only enable this if you know you do not require attributes filled by
+ * this instrumentation to be stable across versions
+ */
+ public AwsSdkTracingBuilder setCaptureExperimentalSpanAttributes(
+ boolean captureExperimentalSpanAttributes) {
+ this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
+ return this;
+ }
+
+ /** Returns a new {@link AwsSdkTracing} with the settings of this {@link AwsSdkTracingBuilder}. */
+ public AwsSdkTracing build() {
+ return new AwsSdkTracing(openTelemetry, captureExperimentalSpanAttributes);
+ }
+}

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java
instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java
package io.opentelemetry.instrumentation.awssdk.v2_2;
-import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getContext;
-import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.tracer;
import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.DynamoDB;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
-import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.core.ClientType;
@@ -27,10 +24,6 @@ import software.amazon.awssdk.http.SdkHttpRequest;
/** AWS request execution interceptor. */
final class TracingExecutionInterceptor implements ExecutionInterceptor {
- private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES =
- Config.get()
- .getBooleanProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", false);
-
// the class name is part of the attribute name, so that it will be shaded when used in javaagent
// instrumentation, and won't conflict with usage outside javaagent instrumentation
static final ExecutionAttribute<io.opentelemetry.context.Context> CONTEXT_ATTRIBUTE =
@@ -42,17 +35,26 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
static final String COMPONENT_NAME = "java-aws-sdk";
- private final FieldMapper fieldMapper = new FieldMapper();
+ private final AwsSdkHttpClientTracer tracer;
+ private final boolean captureExperimentalSpanAttributes;
+ private final FieldMapper fieldMapper;
+
+ TracingExecutionInterceptor(
+ AwsSdkHttpClientTracer tracer, boolean captureExperimentalSpanAttributes) {
+ this.tracer = tracer;
+ this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
+ fieldMapper = new FieldMapper();
+ }
@Override
public void beforeExecution(
Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
io.opentelemetry.context.Context parentOtelContext = io.opentelemetry.context.Context.current();
- if (!tracer().shouldStartSpan(parentOtelContext)) {
+ if (!tracer.shouldStartSpan(parentOtelContext)) {
return;
}
io.opentelemetry.context.Context otelContext =
- tracer().startSpan(parentOtelContext, executionAttributes);
+ tracer.startSpan(parentOtelContext, executionAttributes);
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
if (executionAttributes
.getAttribute(SdkExecutionAttribute.CLIENT_TYPE)
@@ -72,7 +74,7 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
}
SdkHttpRequest.Builder builder = context.httpRequest().toBuilder();
- tracer().inject(otelContext, builder);
+ tracer.inject(otelContext, builder);
return builder.build();
}
@@ -85,7 +87,7 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
}
Span span = Span.fromContext(otelContext);
- tracer().onRequest(span, context.httpRequest());
+ tracer.onRequest(span, context.httpRequest());
AwsSdkRequest awsSdkRequest = AwsSdkRequest.ofSdkRequest(context.request());
if (awsSdkRequest != null) {
@@ -113,7 +115,7 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
}
private void populateGenericAttributes(Span span, ExecutionAttributes attributes) {
- if (CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) {
+ if (captureExperimentalSpanAttributes) {
String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);
String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
@@ -135,18 +137,18 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
Span span = Span.fromContext(otelContext);
onUserAgentHeaderAvailable(span, context.httpRequest());
onSdkResponse(span, context.response(), executionAttributes);
- tracer().end(otelContext, context.httpResponse());
+ tracer.end(otelContext, context.httpResponse());
}
// Certain headers in the request like User-Agent are only available after execution.
private void onUserAgentHeaderAvailable(Span span, SdkHttpRequest request) {
span.setAttribute(
- SemanticAttributes.HTTP_USER_AGENT, tracer().requestHeader(request, "User-Agent"));
+ SemanticAttributes.HTTP_USER_AGENT, tracer.requestHeader(request, "User-Agent"));
}
private void onSdkResponse(
Span span, SdkResponse response, ExecutionAttributes executionAttributes) {
- if (CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) {
+ if (captureExperimentalSpanAttributes) {
if (response instanceof AwsResponse) {
span.setAttribute("aws.requestId", ((AwsResponse) response).responseMetadata().requestId());
}
@@ -162,11 +164,19 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
Context.FailedExecution context, ExecutionAttributes executionAttributes) {
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
clearAttributes(executionAttributes);
- tracer().endExceptionally(otelContext, context.exception());
+ tracer.endExceptionally(otelContext, context.exception());
}
private void clearAttributes(ExecutionAttributes executionAttributes) {
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, null);
executionAttributes.putAttribute(AWS_SDK_REQUEST_ATTRIBUTE, null);
}
+
+ /**
+ * Returns the {@link Context} stored in the {@link ExecutionAttributes}, or {@code null} if there
+ * is no operation set.
+ */
+ private static io.opentelemetry.context.Context getContext(ExecutionAttributes attributes) {
+ return attributes.getAttribute(CONTEXT_ATTRIBUTE);
+ }
}

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2ClientTest.groovy
instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2ClientTest.groovy
@@ -13,7 +13,11 @@ class Aws2ClientTest extends AbstractAws2ClientTest implements LibraryTestTrait
@Override
void configureSdkClient(SdkClientBuilder builder) {
builder.overrideConfiguration(ClientOverrideConfiguration.builder()
- .addExecutionInterceptor(AwsSdk.newInterceptor())
+ .addExecutionInterceptor(
+ AwsSdkTracing.newBuilder(getOpenTelemetry())
+ .setCaptureExperimentalSpanAttributes(true)
+ .build()
+ .newExecutionInterceptor())
.build())
}
}

Migrate AWS SDK v2 to new library API pattern. (#2487)