Automatic AWS library instrumentor
Like AWS X-Ray, provide an instrumentor which automatically registers
opentelemetry instrumentation in the AWS SDK without any code changes.
Those instrumentors are separate libraries published as
opentelemetry-aws-sdk-1.11-instrumentor and opentelemetry-aws-sdk-2.2-instrumentor
ADD
instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/build.gradle.kts
+plugins {
+ id("otel.library-instrumentation")
+}
+
+base.archivesName.set("${base.archivesName.get()}-autoconfigure")
+
+dependencies {
+ implementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:library"))
+
+ library("com.amazonaws:aws-java-sdk-core:1.11.0")
+
+ testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
+
+ testLibrary("com.amazonaws:aws-java-sdk-s3:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-rds:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-ec2:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-sns:1.11.106")
+ testLibrary("com.amazonaws:aws-java-sdk-sqs:1.11.106")
+}
+
+tasks.test {
+ systemProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", "true")
+}

ADD
instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/autoconfigure/TracingRequestHandler.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awssdk.v1_11.autoconfigure;
+
+import com.amazonaws.AmazonWebServiceRequest;
+import com.amazonaws.Request;
+import com.amazonaws.Response;
+import com.amazonaws.handlers.RequestHandler2;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.instrumentation.awssdk.v1_11.AwsSdkTracing;
+
+/**
+ * A {@link RequestHandler2} for use as an SPI by the AWS SDK to automatically trace all requests.
+ */
+public class TracingRequestHandler extends RequestHandler2 {
+
+ private static final RequestHandler2 DELEGATE =
+ AwsSdkTracing.builder(GlobalOpenTelemetry.get())
+ .setCaptureExperimentalSpanAttributes(
+ Config.get()
+ .getBoolean("otel.instrumentation.aws-sdk.experimental-span-attributes", false))
+ .build()
+ .newRequestHandler();
+
+ @Override
+ public void beforeRequest(Request<?> request) {
+ DELEGATE.beforeRequest(request);
+ }
+
+ @Override
+ public AmazonWebServiceRequest beforeMarshalling(AmazonWebServiceRequest request) {
+ return DELEGATE.beforeMarshalling(request);
+ }
+
+ @Override
+ public void afterResponse(Request<?> request, Response<?> response) {
+ DELEGATE.afterResponse(request, response);
+ }
+
+ @Override
+ public void afterError(Request<?> request, Response<?> response, Exception e) {
+ DELEGATE.afterError(request, response, e);
+ }
+}

ADD
instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/resources/com/amazonaws/global/handlers/request.handler2s
+io.opentelemetry.instrumentation.awssdk.v1_11.autoconfigure.TracingRequestHandler
\ No newline at end of file

ADD
instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/instrumentor/Aws1ClientTest.groovy
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awssdk.v1_11.instrumentor
+
+import io.opentelemetry.instrumentation.awssdk.v1_11.AbstractAws1ClientTest
+import io.opentelemetry.instrumentation.test.LibraryTestTrait
+
+class Aws1ClientTest extends AbstractAws1ClientTest implements LibraryTestTrait {
+ @Override
+ def configureClient(def client) {
+ return client
+ }
+}

ADD
instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/instrumentor/SqsTracingTest.groovy
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.awssdk.v1_11.instrumentor
+
+import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder
+import io.opentelemetry.instrumentation.awssdk.v1_11.AbstractSqsTracingTest
+import io.opentelemetry.instrumentation.test.LibraryTestTrait
+
+class SqsTracingTest extends AbstractSqsTracingTest implements LibraryTestTrait {
+ @Override
+ AmazonSQSAsyncClientBuilder configureClient(AmazonSQSAsyncClientBuilder client) {
+ return client
+ }
+}

MODIFY
instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy
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.get(0).getClass().getSimpleName() == "TracingRequestHandler"
+ client.requestHandler2s.find{it.getClass().getSimpleName() == "TracingRequestHandler"} != null
assertTraces(1) {
trace(0, 1) {

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts
@@ -14,7 +14,7 @@ muzzle {
}
dependencies {
- implementation(project(":instrumentation:aws-sdk:aws-sdk-2.2:library"))
+ implementation(project(":instrumentation:aws-sdk:aws-sdk-2.2:library-autoconfigure"))
library("software.amazon.awssdk:aws-core:2.2.0")
@@ -31,3 +31,9 @@ tasks.withType<Test>().configureEach {
// TODO run tests both with and without experimental span attributes
jvmArgs("-Dotel.instrumentation.aws-sdk.experimental-span-attributes=true")
}
+
+tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>().configureEach {
+ mergeServiceFiles {
+ include("software/amazon/awssdk/global/handlers/execution.interceptors")
+ }
+}

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkInstrumentationModule.java
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkInstrumentationModule.java
@@ -10,6 +10,7 @@ import static java.util.Collections.singletonList;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
+import io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure.TracingExecutionInterceptor;
import io.opentelemetry.javaagent.extension.instrumentation.HelperResourceBuilder;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;

DELETE
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors
-io.opentelemetry.javaagent.instrumentation.awssdk.v2_2.TracingExecutionInterceptor

ADD
instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/build.gradle.kts
+plugins {
+ id("otel.library-instrumentation")
+}
+
+base.archivesName.set("${base.archivesName.get()}-autoconfigure")
+
+dependencies {
+ implementation(project(":instrumentation:aws-sdk:aws-sdk-2.2:library"))
+
+ library("software.amazon.awssdk:aws-core:2.2.0")
+ library("software.amazon.awssdk:aws-json-protocol:2.2.0")
+
+ testImplementation(project(":instrumentation:aws-sdk:aws-sdk-2.2:testing"))
+
+ latestDepTestLibrary("software.amazon.awssdk:kinesis:+")
+}
+
+tasks {
+ test {
+ systemProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", true)
+ }
+}

RENAME
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/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/autoconfigure/TracingExecutionInterceptor.java
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.awssdk.v2_2;
+package io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.config.Config;
@@ -15,19 +15,7 @@ import org.reactivestreams.Publisher;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.SdkResponse;
import software.amazon.awssdk.core.async.AsyncRequestBody;
-import software.amazon.awssdk.core.interceptor.Context.AfterExecution;
-import software.amazon.awssdk.core.interceptor.Context.AfterMarshalling;
-import software.amazon.awssdk.core.interceptor.Context.AfterTransmission;
-import software.amazon.awssdk.core.interceptor.Context.AfterUnmarshalling;
-import software.amazon.awssdk.core.interceptor.Context.BeforeExecution;
-import software.amazon.awssdk.core.interceptor.Context.BeforeMarshalling;
-import software.amazon.awssdk.core.interceptor.Context.BeforeTransmission;
-import software.amazon.awssdk.core.interceptor.Context.BeforeUnmarshalling;
-import software.amazon.awssdk.core.interceptor.Context.FailedExecution;
-import software.amazon.awssdk.core.interceptor.Context.ModifyHttpRequest;
-import software.amazon.awssdk.core.interceptor.Context.ModifyHttpResponse;
-import software.amazon.awssdk.core.interceptor.Context.ModifyRequest;
-import software.amazon.awssdk.core.interceptor.Context.ModifyResponse;
+import software.amazon.awssdk.core.interceptor.Context;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.awssdk.core.sync.RequestBody;
@@ -35,125 +23,125 @@ import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SdkHttpResponse;
/**
- * {@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.
+ * A {@link ExecutionInterceptor} for use as an SPI by the AWS SDK to automatically trace all
+ * requests.
*/
public class TracingExecutionInterceptor implements ExecutionInterceptor {
private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES =
Config.get().getBoolean("otel.instrumentation.aws-sdk.experimental-span-attributes", false);
- private final ExecutionInterceptor delegate;
-
- public TracingExecutionInterceptor() {
- delegate =
+ private final ExecutionInterceptor delegate =
AwsSdkTracing.builder(GlobalOpenTelemetry.get())
.setCaptureExperimentalSpanAttributes(CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES)
.build()
.newExecutionInterceptor();
- }
@Override
- public void beforeExecution(BeforeExecution context, ExecutionAttributes executionAttributes) {
+ public void beforeExecution(
+ Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
delegate.beforeExecution(context, executionAttributes);
}
@Override
- public SdkRequest modifyRequest(ModifyRequest context, ExecutionAttributes executionAttributes) {
+ public SdkRequest modifyRequest(
+ Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
return delegate.modifyRequest(context, executionAttributes);
}
@Override
public void beforeMarshalling(
- BeforeMarshalling context, ExecutionAttributes executionAttributes) {
+ Context.BeforeMarshalling context, ExecutionAttributes executionAttributes) {
delegate.beforeMarshalling(context, executionAttributes);
}
@Override
- public void afterMarshalling(AfterMarshalling context, ExecutionAttributes executionAttributes) {
+ public void afterMarshalling(
+ Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
delegate.afterMarshalling(context, executionAttributes);
}
@Override
public SdkHttpRequest modifyHttpRequest(
- ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
return delegate.modifyHttpRequest(context, executionAttributes);
}
@Override
public Optional<RequestBody> modifyHttpContent(
- ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
return delegate.modifyHttpContent(context, executionAttributes);
}
@Override
public Optional<AsyncRequestBody> modifyAsyncHttpContent(
- ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
return delegate.modifyAsyncHttpContent(context, executionAttributes);
}
@Override
public void beforeTransmission(
- BeforeTransmission context, ExecutionAttributes executionAttributes) {
+ Context.BeforeTransmission context, ExecutionAttributes executionAttributes) {
delegate.beforeTransmission(context, executionAttributes);
}
@Override
public void afterTransmission(
- AfterTransmission context, ExecutionAttributes executionAttributes) {
+ Context.AfterTransmission context, ExecutionAttributes executionAttributes) {
delegate.afterTransmission(context, executionAttributes);
}
@Override
public SdkHttpResponse modifyHttpResponse(
- ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
return delegate.modifyHttpResponse(context, executionAttributes);
}
@Override
public Optional<Publisher<ByteBuffer>> modifyAsyncHttpResponseContent(
- ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
return delegate.modifyAsyncHttpResponseContent(context, executionAttributes);
}
@Override
public Optional<InputStream> modifyHttpResponseContent(
- ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
+ Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes) {
return delegate.modifyHttpResponseContent(context, executionAttributes);
}
@Override
public void beforeUnmarshalling(
- BeforeUnmarshalling context, ExecutionAttributes executionAttributes) {
+ Context.BeforeUnmarshalling context, ExecutionAttributes executionAttributes) {
delegate.beforeUnmarshalling(context, executionAttributes);
}
@Override
public void afterUnmarshalling(
- AfterUnmarshalling context, ExecutionAttributes executionAttributes) {
+ Context.AfterUnmarshalling context, ExecutionAttributes executionAttributes) {
delegate.afterUnmarshalling(context, executionAttributes);
}
@Override
public SdkResponse modifyResponse(
- ModifyResponse context, ExecutionAttributes executionAttributes) {
+ Context.ModifyResponse context, ExecutionAttributes executionAttributes) {
return delegate.modifyResponse(context, executionAttributes);
}
@Override
- public void afterExecution(AfterExecution context, ExecutionAttributes executionAttributes) {
+ public void afterExecution(
+ Context.AfterExecution context, ExecutionAttributes executionAttributes) {
delegate.afterExecution(context, executionAttributes);
}
@Override
public Throwable modifyException(
- FailedExecution context, ExecutionAttributes executionAttributes) {
+ Context.FailedExecution context, ExecutionAttributes executionAttributes) {
return delegate.modifyException(context, executionAttributes);
}
@Override
- public void onExecutionFailure(FailedExecution context, ExecutionAttributes executionAttributes) {
+ public void onExecutionFailure(
+ Context.FailedExecution context, ExecutionAttributes executionAttributes) {
delegate.onExecutionFailure(context, executionAttributes);
}
}

ADD
instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors
+io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure.TracingExecutionInterceptor
\ No newline at end of file

ADD
instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/test/groovy/v2_2/Aws2ClientTest.groovy
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package v2_2
+
+import io.opentelemetry.instrumentation.awssdk.v2_2.AbstractAws2ClientTest
+import io.opentelemetry.instrumentation.test.LibraryTestTrait
+import software.amazon.awssdk.core.client.builder.SdkClientBuilder
+
+class Aws2ClientTest extends AbstractAws2ClientTest implements LibraryTestTrait {
+ @Override
+ void configureSdkClient(SdkClientBuilder builder) {
+ }
+}

MODIFY
instrumentation/aws-sdk/aws-sdk-2.2/library/README.md
instrumentation/aws-sdk/aws-sdk-2.2/library/README.md
@@ -4,7 +4,9 @@ Instrumentation for [AWS Java SDK v2](https://github.com/aws/aws-sdk-java-v2).
## Usage
-To register instrumentation on an SDK client, register the interceptor when creating it.
+To instrument all AWS SDK clients include the `opentelemetry-aws-sdk-2.2-autoconfigure` submodule in your classpath.
+
+To register instrumentation only on a specific SDK client, register the interceptor when creating it.
```java
DynamoDbClient client = DynamoDbClient.builder()

MODIFY
settings.gradle.kts
settings.gradle.kts
@@ -127,9 +127,11 @@ include(":instrumentation:aws-lambda-1.0:testing")
include(":instrumentation:aws-sdk:aws-sdk-1.11:javaagent")
include(":instrumentation:aws-sdk:aws-sdk-1.11:javaagent-unit-tests")
include(":instrumentation:aws-sdk:aws-sdk-1.11:library")
+include(":instrumentation:aws-sdk:aws-sdk-1.11:library-autoconfigure")
include(":instrumentation:aws-sdk:aws-sdk-1.11:testing")
include(":instrumentation:aws-sdk:aws-sdk-2.2:javaagent")
include(":instrumentation:aws-sdk:aws-sdk-2.2:library")
+include(":instrumentation:aws-sdk:aws-sdk-2.2:library-autoconfigure")
include(":instrumentation:aws-sdk:aws-sdk-2.2:testing")
include(":instrumentation:cassandra:cassandra-3.0:javaagent")
include(":instrumentation:cassandra:cassandra-4.0:javaagent")

Automatic AWS library instrumentor (#4607)

Like AWS X-Ray, provide an instrumentor which automatically registers
opentelemetry instrumentation in the AWS SDK without any code changes.
Those instrumentors are separate libraries published as
opentelemetry-aws-sdk-1.11-instrumentor and opentelemetry-aws-sdk-2.2-instrumentor