aws-sdk-1.1: Copy SQS plugin/NoMuzzle approach from 2.2 (#8866)
Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com>
This commit is contained in:
parent
40938cf9e2
commit
ba2f8d209f
|
@ -15,6 +15,22 @@ muzzle {
|
|||
module.set("aws-java-sdk-core")
|
||||
versions.set("[1.10.33,)")
|
||||
assertInverse.set(true)
|
||||
|
||||
excludeInstrumentationName("aws-sdk-1.11-sqs")
|
||||
}
|
||||
|
||||
fail {
|
||||
group.set("com.amazonaws")
|
||||
module.set("aws-java-sdk-core")
|
||||
versions.set("[1.10.33,)")
|
||||
|
||||
excludeInstrumentationName("aws-sdk-1.11-core")
|
||||
}
|
||||
|
||||
pass {
|
||||
group.set("com.amazonaws")
|
||||
module.set("aws-java-sdk-sqs")
|
||||
versions.set("[1.10.33,)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
public final class SqsAdviceBridge {
|
||||
private SqsAdviceBridge() {}
|
||||
|
||||
public static void referenceForMuzzleOnly() {
|
||||
throw new UnsupportedOperationException(
|
||||
SqsImpl.class.getName() + " referencing for muzzle, should never be actually called");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
// TODO: Copy & paste with only trivial adaptions from v2
|
||||
abstract class AbstractAwsSdkInstrumentationModule extends InstrumentationModule {
|
||||
|
||||
protected AbstractAwsSdkInstrumentationModule(String additionalInstrumentationName) {
|
||||
super("aws-sdk", "aws-sdk-1.11", additionalInstrumentationName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHelperClass(String className) {
|
||||
return className.startsWith("io.opentelemetry.contrib.awsxray.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||
// We don't actually transform it but want to make sure we only apply the instrumentation when
|
||||
// our key dependency is present.
|
||||
return hasClassesNamed("com.amazonaws.AmazonWebServiceClient");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ResourceInjectingTypeInstrumentation());
|
||||
}
|
||||
|
||||
abstract void doTransform(TypeTransformer transformer);
|
||||
|
||||
// A type instrumentation is needed to trigger resource injection.
|
||||
public class ResourceInjectingTypeInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
// This is essentially the entry point of the AWS SDK, all clients implement it. We can ensure
|
||||
// our interceptor service definition is injected as early as possible if we typematch against
|
||||
// it.
|
||||
return named("com.amazonaws.AmazonWebServiceClient");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(TypeTransformer transformer) {
|
||||
doTransform(transformer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
@AutoService(InstrumentationModule.class)
|
||||
public class AwsSdkInstrumentationModule extends InstrumentationModule {
|
||||
public AwsSdkInstrumentationModule() {
|
||||
super("aws-sdk", "aws-sdk-1.11");
|
||||
super("aws-sdk", "aws-sdk-1.11", "aws-sdk-1.11-core");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.none;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.instrumentation.awssdk.v1_11.SqsAdviceBridge;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class SqsInstrumentationModule extends AbstractAwsSdkInstrumentationModule {
|
||||
|
||||
public SqsInstrumentationModule() {
|
||||
super("aws-sdk-1.11-sqs");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTransform(TypeTransformer transformer) {
|
||||
transformer.applyAdviceToMethod(
|
||||
none(), SqsInstrumentationModule.class.getName() + "$RegisterAdvice");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class RegisterAdvice {
|
||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void onExit() {
|
||||
// (indirectly) using SqsImpl class here to make sure it is available from SqsAccess
|
||||
// (injected into app classloader) and checked by Muzzle
|
||||
SqsAdviceBridge.referenceForMuzzleOnly();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@ dependencies {
|
|||
implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
|
||||
|
||||
library("com.amazonaws:aws-java-sdk-core:1.11.0")
|
||||
library("com.amazonaws:aws-java-sdk-sqs:1.11.106")
|
||||
compileOnly(project(":muzzle"))
|
||||
|
||||
testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
|
||||
|
||||
|
@ -15,5 +17,4 @@ dependencies {
|
|||
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")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
final class PluginImplUtil { // TODO: Copy & paste from v2
|
||||
private PluginImplUtil() {}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PluginImplUtil.class.getName());
|
||||
|
||||
/**
|
||||
* Check if the given {@code moduleNameImpl} is present.
|
||||
*
|
||||
* <p>For library instrumentations, the Impls will always be available but might fail to
|
||||
* load/link/initialize 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).
|
||||
*
|
||||
* <p>Note that an present-but-incompatible library can only be reliably 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) {
|
||||
// Computing the full name dynamically name here because library instrumentation classes are
|
||||
// relocated when embedded in the agent.
|
||||
// We use getName().replace() instead of getPackage() because the latter is not guaranteed to
|
||||
// work in all cases (e.g., we might be loaded into a custom classloader that doesn't handle it)
|
||||
String implFullClassName =
|
||||
PluginImplUtil.class.getName().replace(".PluginImplUtil", "." + implSimpleClassName);
|
||||
try {
|
||||
Class.forName(implFullClassName);
|
||||
return true;
|
||||
} catch (ClassNotFoundException | LinkageError e) {
|
||||
// ClassNotFoundException will happen when muzzle disabled us in javaagent mode; LinkageError
|
||||
// (most likely a NoClassDefFoundError, potentially wrapped in an ExceptionInInitializerError)
|
||||
// should be thrown when the class is loaded in library mode (where the Impl class itself can
|
||||
// always be found) 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. "
|
||||
+ "Most likely, corresponding SDK component is either not on classpath or incompatible.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
|
||||
|
||||
final class SqsAccess {
|
||||
private SqsAccess() {}
|
||||
|
||||
private static final boolean enabled = PluginImplUtil.isImplPresent("SqsImpl");
|
||||
|
||||
@NoMuzzle
|
||||
static boolean afterResponse(
|
||||
Request<?> request,
|
||||
Response<?> response,
|
||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
||||
return enabled && SqsImpl.afterResponse(request, response, consumerInstrumenter);
|
||||
}
|
||||
|
||||
@NoMuzzle
|
||||
static boolean beforeMarshalling(AmazonWebServiceRequest request) {
|
||||
return enabled && SqsImpl.beforeMarshalling(request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import com.amazonaws.services.sqs.AmazonSQS;
|
||||
import com.amazonaws.services.sqs.model.Message;
|
||||
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
|
||||
import com.amazonaws.services.sqs.model.ReceiveMessageResult;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
|
||||
final class SqsImpl {
|
||||
static {
|
||||
// Force loading of SQS class; this ensures that an exception is thrown at this point when the
|
||||
// SQS library is not present, which will cause SqsAccess to have enabled=false in library mode.
|
||||
@SuppressWarnings("unused")
|
||||
String ensureLoadedDummy = AmazonSQS.class.getName();
|
||||
}
|
||||
|
||||
private SqsImpl() {}
|
||||
|
||||
static boolean afterResponse(
|
||||
Request<?> request,
|
||||
Response<?> response,
|
||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
||||
if (response.getAwsResponse() instanceof ReceiveMessageResult) {
|
||||
afterConsumerResponse(request, response, consumerInstrumenter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Create and close CONSUMER span for each message consumed. */
|
||||
private static void afterConsumerResponse(
|
||||
Request<?> request,
|
||||
Response<?> response,
|
||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
||||
ReceiveMessageResult receiveMessageResult = (ReceiveMessageResult) response.getAwsResponse();
|
||||
for (Message message : receiveMessageResult.getMessages()) {
|
||||
createConsumerSpan(message, request, response, consumerInstrumenter);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createConsumerSpan(
|
||||
Message message,
|
||||
Request<?> request,
|
||||
Response<?> response,
|
||||
Instrumenter<Request<?>, Response<?>> consumerInstrumenter) {
|
||||
Context parentContext = SqsParentContext.ofSystemAttributes(message.getAttributes());
|
||||
Context context = consumerInstrumenter.start(parentContext, request);
|
||||
consumerInstrumenter.end(context, request, response, null);
|
||||
}
|
||||
|
||||
static boolean beforeMarshalling(AmazonWebServiceRequest rawRequest) {
|
||||
if (rawRequest instanceof ReceiveMessageRequest) {
|
||||
ReceiveMessageRequest request = (ReceiveMessageRequest) rawRequest;
|
||||
if (!request.getAttributeNames().contains(SqsParentContext.AWS_TRACE_SYSTEM_ATTRIBUTE)) {
|
||||
request.withAttributeNames(SqsParentContext.AWS_TRACE_SYSTEM_ATTRIBUTE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Reflective access to aws-sdk-java-sqs class Message.
|
||||
*
|
||||
* <p>We currently don't have a good pattern of instrumenting a core library with various plugins
|
||||
* that need plugin-specific instrumentation - if we accessed the class directly, Muzzle would
|
||||
* prevent the entire instrumentation from loading when the plugin isn't available. We need to
|
||||
* carefully check this class has all reflection errors result in no-op, and in the future we will
|
||||
* hopefully come up with a better pattern.
|
||||
*/
|
||||
final class SqsMessageAccess {
|
||||
|
||||
@Nullable private static final MethodHandle GET_ATTRIBUTES;
|
||||
|
||||
static {
|
||||
Class<?> messageClass = null;
|
||||
try {
|
||||
messageClass = Class.forName("com.amazonaws.services.sqs.model.Message");
|
||||
} catch (Throwable t) {
|
||||
// Ignore.
|
||||
}
|
||||
if (messageClass != null) {
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
MethodHandle getAttributes = null;
|
||||
try {
|
||||
getAttributes = lookup.findVirtual(messageClass, "getAttributes", methodType(Map.class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
GET_ATTRIBUTES = getAttributes;
|
||||
} else {
|
||||
GET_ATTRIBUTES = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, String> getAttributes(Object message) {
|
||||
if (GET_ATTRIBUTES == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try {
|
||||
return (Map<String, String>) GET_ATTRIBUTES.invoke(message);
|
||||
} catch (Throwable t) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
private SqsMessageAccess() {}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Reflective access to aws-sdk-java-sqs class ReceiveMessageRequest.
|
||||
*
|
||||
* <p>We currently don't have a good pattern of instrumenting a core library with various plugins
|
||||
* that need plugin-specific instrumentation - if we accessed the class directly, Muzzle would
|
||||
* prevent the entire instrumentation from loading when the plugin isn't available. We need to
|
||||
* carefully check this class has all reflection errors result in no-op, and in the future we will
|
||||
* hopefully come up with a better pattern.
|
||||
*/
|
||||
final class SqsReceiveMessageRequestAccess {
|
||||
|
||||
@Nullable private static final MethodHandle WITH_ATTRIBUTE_NAMES;
|
||||
@Nullable private static final MethodHandle GET_ATTRIBUTE_NAMES;
|
||||
|
||||
static {
|
||||
Class<?> receiveMessageRequestClass = null;
|
||||
try {
|
||||
receiveMessageRequestClass =
|
||||
Class.forName("com.amazonaws.services.sqs.model.ReceiveMessageRequest");
|
||||
} catch (Throwable t) {
|
||||
// Ignore.
|
||||
}
|
||||
if (receiveMessageRequestClass != null) {
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
MethodHandle withAttributeNames = null;
|
||||
try {
|
||||
withAttributeNames =
|
||||
lookup.findVirtual(
|
||||
receiveMessageRequestClass,
|
||||
"withAttributeNames",
|
||||
methodType(receiveMessageRequestClass, String[].class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
WITH_ATTRIBUTE_NAMES = withAttributeNames;
|
||||
|
||||
MethodHandle getAttributeNames = null;
|
||||
try {
|
||||
getAttributeNames =
|
||||
lookup.findVirtual(
|
||||
receiveMessageRequestClass, "getAttributeNames", methodType(List.class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
GET_ATTRIBUTE_NAMES = getAttributeNames;
|
||||
} else {
|
||||
WITH_ATTRIBUTE_NAMES = null;
|
||||
GET_ATTRIBUTE_NAMES = null;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isInstance(AmazonWebServiceRequest request) {
|
||||
return request
|
||||
.getClass()
|
||||
.getName()
|
||||
.equals("com.amazonaws.services.sqs.model.ReceiveMessageRequest");
|
||||
}
|
||||
|
||||
static void withAttributeNames(AmazonWebServiceRequest request, String name) {
|
||||
if (WITH_ATTRIBUTE_NAMES == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
WITH_ATTRIBUTE_NAMES.invoke(request, name);
|
||||
} catch (Throwable throwable) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<String> getAttributeNames(AmazonWebServiceRequest request) {
|
||||
if (GET_ATTRIBUTE_NAMES == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
return (List<String>) GET_ATTRIBUTE_NAMES.invoke(request);
|
||||
} catch (Throwable t) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private SqsReceiveMessageRequestAccess() {}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v1_11;
|
||||
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Reflective access to aws-sdk-java-sqs class ReceiveMessageResult.
|
||||
*
|
||||
* <p>We currently don't have a good pattern of instrumenting a core library with various plugins
|
||||
* that need plugin-specific instrumentation - if we accessed the class directly, Muzzle would
|
||||
* prevent the entire instrumentation from loading when the plugin isn't available. We need to
|
||||
* carefully check this class has all reflection errors result in no-op, and in the future we will
|
||||
* hopefully come up with a better pattern.
|
||||
*/
|
||||
final class SqsReceiveMessageResultAccess {
|
||||
|
||||
@Nullable private static final MethodHandle GET_MESSAGES;
|
||||
|
||||
static {
|
||||
Class<?> receiveMessageResultClass = null;
|
||||
try {
|
||||
receiveMessageResultClass =
|
||||
Class.forName("com.amazonaws.services.sqs.model.ReceiveMessageResult");
|
||||
} catch (Throwable t) {
|
||||
// Ignore.
|
||||
}
|
||||
if (receiveMessageResultClass != null) {
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
MethodHandle getMessages = null;
|
||||
try {
|
||||
getMessages =
|
||||
lookup.findVirtual(receiveMessageResultClass, "getMessages", methodType(List.class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
// Ignore
|
||||
}
|
||||
GET_MESSAGES = getMessages;
|
||||
} else {
|
||||
GET_MESSAGES = null;
|
||||
}
|
||||
}
|
||||
|
||||
static List<?> getMessages(Object result) {
|
||||
if (GET_MESSAGES == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
return (List<?>) GET_MESSAGES.invoke(result);
|
||||
} catch (Throwable t) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private SqsReceiveMessageResultAccess() {}
|
||||
}
|
|
@ -14,7 +14,6 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
|||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.contrib.awsxray.propagator.AwsXrayPropagator;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Tracing Request Handler. */
|
||||
|
@ -58,40 +57,18 @@ final class TracingRequestHandler extends RequestHandler2 {
|
|||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
public AmazonWebServiceRequest beforeMarshalling(AmazonWebServiceRequest request) {
|
||||
if (SqsReceiveMessageRequestAccess.isInstance(request)) {
|
||||
if (!SqsReceiveMessageRequestAccess.getAttributeNames(request)
|
||||
.contains(SqsParentContext.AWS_TRACE_SYSTEM_ATTRIBUTE)) {
|
||||
SqsReceiveMessageRequestAccess.withAttributeNames(
|
||||
request, SqsParentContext.AWS_TRACE_SYSTEM_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
// TODO: We are modifying the request in-place instead of using clone() as recommended
|
||||
// by the Javadoc in the interface.
|
||||
SqsAccess.beforeMarshalling(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterResponse(Request<?> request, Response<?> response) {
|
||||
if (SqsReceiveMessageRequestAccess.isInstance(request.getOriginalRequest())) {
|
||||
afterConsumerResponse(request, response);
|
||||
}
|
||||
SqsAccess.afterResponse(request, response, consumerInstrumenter);
|
||||
finish(request, response, null);
|
||||
}
|
||||
|
||||
/** Create and close CONSUMER span for each message consumed. */
|
||||
private void afterConsumerResponse(Request<?> request, Response<?> response) {
|
||||
Object receiveMessageResult = response.getAwsResponse();
|
||||
List<?> messages = SqsReceiveMessageResultAccess.getMessages(receiveMessageResult);
|
||||
for (Object message : messages) {
|
||||
createConsumerSpan(message, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void createConsumerSpan(Object message, Request<?> request, Response<?> response) {
|
||||
Context parentContext =
|
||||
SqsParentContext.ofSystemAttributes(SqsMessageAccess.getAttributes(message));
|
||||
Context context = consumerInstrumenter.start(parentContext, request);
|
||||
consumerInstrumenter.end(context, request, response, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterError(Request<?> request, Response<?> response, Exception e) {
|
||||
finish(request, response, e);
|
||||
|
|
|
@ -8,7 +8,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
final class PluginImplUtil {
|
||||
final class PluginImplUtil { // TODO: Copy & pasted to v1
|
||||
private PluginImplUtil() {}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PluginImplUtil.class.getName());
|
||||
|
@ -16,33 +16,40 @@ final class PluginImplUtil {
|
|||
/**
|
||||
* Check if the given {@code moduleNameImpl} is present.
|
||||
*
|
||||
* <p>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).
|
||||
* <p>For library instrumentations, the Impls will always be available but might fail to
|
||||
* load/link/initialize 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).
|
||||
*
|
||||
* <p>Note that an present-but-incompatible library can only be detected by Muzzle. In
|
||||
* <p>Note that an present-but-incompatible library can only be reliably 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) {
|
||||
// Computing the full name dynamically name here because library instrumentation classes are
|
||||
// relocated when embedded in the agent.
|
||||
// We use getName().replace() instead of getPackage() because the latter is not guaranteed to
|
||||
// work in all cases (e.g., we might be loaded into a custom classloader that doesn't handle it)
|
||||
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).
|
||||
// (most likely a NoClassDefFoundError, potentially wrapped in an ExceptionInInitializerError)
|
||||
// should be thrown when the class is loaded in library mode (where the Impl class itself can
|
||||
// always be found) 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");
|
||||
Level.FINE,
|
||||
e,
|
||||
() ->
|
||||
implFullClassName
|
||||
+ " not present. "
|
||||
+ "Most likely, corresponding SDK component is either not on classpath or incompatible.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue