diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/PluginImplUtil.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/PluginImplUtil.java new file mode 100644 index 000000000000..2c19349efea7 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/PluginImplUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import java.util.logging.Level; +import java.util.logging.Logger; + +final class PluginImplUtil { + private PluginImplUtil() {} + + private static final Logger logger = Logger.getLogger(PluginImplUtil.class.getName()); + + /** + * Check if the given {@code moduleNameImpl} is present. + * + *
For library instrumentations, the Impls will always be available but might fail to load if + * the corresponding SDK classes are not on the class path. For javaagent, the Impl is available + * only when the corresponding InstrumentationModule was successfully applied (muzzle passed). + * + *
Note that an present-but-incompatible library can only be detected by Muzzle. In + * library-mode, users need to ensure they are using a compatible SDK (component) versions + * themselves. + * + * @param implSimpleClassName The simple name of the impl class, e.g. {@code "SqsImpl"}. * + */ + static boolean isImplPresent(String implSimpleClassName) { + String implFullClassName = + PluginImplUtil.class.getName().replace(".PluginImplUtil", "." + implSimpleClassName); + try { + // using package name here because library instrumentation classes are relocated when embedded + // in the agent + Class.forName(implFullClassName); + return true; + } catch (ClassNotFoundException | LinkageError e) { + // ClassNotFoundException will happen when muzzle disabled us in javaagent mode; LinkageError + // (most likely NoClassDefFoundError) should happen when the class is loaded in library mode + // (where it is always available) but a dependency failed to load (most likely because the + // corresponding SDK dependency is not on the class path). + logger.log( + Level.FINE, e, () -> implFullClassName + " not present, probably incompatible version"); + return false; + } + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsAccess.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsAccess.java index f1f8aad68dd1..22a41c4bbb41 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsAccess.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsAccess.java @@ -20,21 +20,7 @@ final class SqsAccess { private SqsAccess() {} - private static final boolean enabled = isSqsImplPresent(); - - private static boolean isSqsImplPresent() { - try { - // for library instrumentation SqsImpl is always available - // for javaagent instrumentation SqsImpl is available only when SqsInstrumentationModule was - // successfully applied (muzzle passed) - // using package name here because library instrumentation classes are relocated when embedded - // in the agent - Class.forName(SqsAccess.class.getName().replace(".SqsAccess", ".SqsImpl")); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } + private static final boolean enabled = PluginImplUtil.isImplPresent("SqsImpl"); @NoMuzzle static boolean isSendMessageRequest(SdkRequest request) { diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsImpl.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsImpl.java index df3b402206f8..50eacb7985b1 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsImpl.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SqsImpl.java @@ -15,6 +15,7 @@ import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.services.sqs.SqsClient; import software.amazon.awssdk.services.sqs.model.Message; import software.amazon.awssdk.services.sqs.model.MessageAttributeValue; import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; @@ -23,6 +24,13 @@ // this class is only used from SqsAccess from method with @NoMuzzle annotation final class SqsImpl { + static { + // Force loading of SqsClient; this ensures that an exception is thrown at this point when the + // SQS library is not present, which will cause SnsAccess to have enabled=false in library mode. + @SuppressWarnings("unused") + String ensureLoadedDummy = SqsClient.class.getName(); + } + private SqsImpl() {} static SdkRequest injectIntoSendMessageRequest(