Support looking up a ContextStore from outside of Advice (#3827)
* Support looking up a ContextStore from outside of Advice * Add exception message * Move setting ContextStoreSupplier * Improve comment
This commit is contained in:
parent
6dbb64ec7a
commit
667b87bac7
|
@ -18,7 +18,12 @@ public class InstrumentationContext {
|
||||||
* <p>In reality, the <em>calls</em> to this method are re-written to something more performant
|
* <p>In reality, the <em>calls</em> to this method are re-written to something more performant
|
||||||
* while injecting advice into a method.
|
* while injecting advice into a method.
|
||||||
*
|
*
|
||||||
* <p>This method must only be called within an Advice class.
|
* <p>When this method is called from outside of an Advice class it can only access {@link
|
||||||
|
* ContextStore} when it is already created. For this {@link ContextStore} either needs to be
|
||||||
|
* added to {@code
|
||||||
|
* io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule#getMuzzleContextStoreClasses()}
|
||||||
|
* or be used in an Advice or Helper class which automatically adds it to {@code
|
||||||
|
* InstrumentationModule#getMuzzleContextStoreClasses()}
|
||||||
*
|
*
|
||||||
* @param keyClass The key class context is attached to.
|
* @param keyClass The key class context is attached to.
|
||||||
* @param contextClass The context class attached to the user class.
|
* @param contextClass The context class attached to the user class.
|
||||||
|
@ -28,7 +33,27 @@ public class InstrumentationContext {
|
||||||
*/
|
*/
|
||||||
public static <Q extends K, K, C> ContextStore<Q, C> get(
|
public static <Q extends K, K, C> ContextStore<Q, C> get(
|
||||||
Class<K> keyClass, Class<C> contextClass) {
|
Class<K> keyClass, Class<C> contextClass) {
|
||||||
throw new IllegalStateException(
|
if (contextStoreSupplier == null) {
|
||||||
"Calls to this method will be rewritten by Instrumentation Context Provider (e.g. FieldBackedProvider)");
|
throw new IllegalStateException("Context store supplier not set");
|
||||||
|
}
|
||||||
|
return contextStoreSupplier.get(keyClass, contextClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ContextStoreSupplier<Q extends K, K, C> {
|
||||||
|
ContextStore<Q, C> get(Class<K> keyClass, Class<C> contextClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static volatile ContextStoreSupplier contextStoreSupplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link ContextStoreSupplier} to execute when instrumentation needs to access {@link
|
||||||
|
* ContextStore}. This is called from the agent startup, instrumentation must not call this.
|
||||||
|
*/
|
||||||
|
public static void internalSetContextStoreSupplier(ContextStoreSupplier contextStoreSupplier) {
|
||||||
|
if (InstrumentationContext.contextStoreSupplier != null) {
|
||||||
|
// Only possible by misuse of this API, just ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InstrumentationContext.contextStoreSupplier = contextStoreSupplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.opentelemetry.javaagent.tooling.TransformSafeLogger;
|
||||||
import io.opentelemetry.javaagent.tooling.Utils;
|
import io.opentelemetry.javaagent.tooling.Utils;
|
||||||
import io.opentelemetry.javaagent.tooling.instrumentation.InstrumentationModuleInstaller;
|
import io.opentelemetry.javaagent.tooling.instrumentation.InstrumentationModuleInstaller;
|
||||||
import java.lang.instrument.Instrumentation;
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -139,6 +140,21 @@ public class FieldBackedProvider implements InstrumentationContextProvider {
|
||||||
bootstrapHelperInjector(contextStoreImplementations.values());
|
bootstrapHelperInjector(contextStoreImplementations.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <Q extends K, K, C> ContextStore<Q, C> getContextStore(
|
||||||
|
Class<K> keyClass, Class<C> contextClass) {
|
||||||
|
try {
|
||||||
|
String contextStoreClassName =
|
||||||
|
getContextStoreImplementationClassName(keyClass.getName(), contextClass.getName());
|
||||||
|
Class<?> contextStoreClass = Class.forName(contextStoreClassName, false, null);
|
||||||
|
Method method = contextStoreClass.getMethod("getContextStore", Class.class, Class.class);
|
||||||
|
return (ContextStore<Q, C>) method.invoke(null, keyClass, contextClass);
|
||||||
|
} catch (ClassNotFoundException exception) {
|
||||||
|
throw new IllegalStateException("Context store not found", exception);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException exception) {
|
||||||
|
throw new IllegalStateException("Failed to get context store", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AgentBuilder.Identified.Extendable instrumentationTransformer(
|
public AgentBuilder.Identified.Extendable instrumentationTransformer(
|
||||||
AgentBuilder.Identified.Extendable builder) {
|
AgentBuilder.Identified.Extendable builder) {
|
||||||
|
@ -989,10 +1005,10 @@ public class FieldBackedProvider implements InstrumentationContextProvider {
|
||||||
return (builder, typeDescription, classLoader, module) -> builder.visit(visitor);
|
return (builder, typeDescription, classLoader, module) -> builder.visit(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getContextStoreImplementationClassName(
|
private static String getContextStoreImplementationClassName(
|
||||||
String keyClassName, String contextClassName) {
|
String keyClassName, String contextClassName) {
|
||||||
return DYNAMIC_CLASSES_PACKAGE
|
return DYNAMIC_CLASSES_PACKAGE
|
||||||
+ getClass().getSimpleName()
|
+ FieldBackedProvider.class.getSimpleName()
|
||||||
+ "$ContextStore$"
|
+ "$ContextStore$"
|
||||||
+ Utils.convertToInnerClassName(keyClassName)
|
+ Utils.convertToInnerClassName(keyClassName)
|
||||||
+ "$"
|
+ "$"
|
||||||
|
|
|
@ -12,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
|
||||||
import io.opentelemetry.javaagent.tooling.HelperInjector;
|
import io.opentelemetry.javaagent.tooling.HelperInjector;
|
||||||
import io.opentelemetry.javaagent.tooling.TransformSafeLogger;
|
import io.opentelemetry.javaagent.tooling.TransformSafeLogger;
|
||||||
import io.opentelemetry.javaagent.tooling.Utils;
|
import io.opentelemetry.javaagent.tooling.Utils;
|
||||||
|
@ -113,12 +114,23 @@ public final class InstrumentationModuleInstaller {
|
||||||
InstrumentationModule instrumentationModule) {
|
InstrumentationModule instrumentationModule) {
|
||||||
Map<String, String> contextStore = instrumentationModule.getMuzzleContextStoreClasses();
|
Map<String, String> contextStore = instrumentationModule.getMuzzleContextStoreClasses();
|
||||||
if (!contextStore.isEmpty()) {
|
if (!contextStore.isEmpty()) {
|
||||||
return new FieldBackedProvider(instrumentationModule.getClass(), contextStore);
|
return FieldBackedProviderFactory.get(instrumentationModule.getClass(), contextStore);
|
||||||
} else {
|
} else {
|
||||||
return NoopContextProvider.INSTANCE;
|
return NoopContextProvider.INSTANCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class FieldBackedProviderFactory {
|
||||||
|
static {
|
||||||
|
InstrumentationContext.internalSetContextStoreSupplier(
|
||||||
|
(keyClass, contextClass) -> FieldBackedProvider.getContextStore(keyClass, contextClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldBackedProvider get(Class<?> instrumenterClass, Map<String, String> contextStore) {
|
||||||
|
return new FieldBackedProvider(instrumenterClass, contextStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ByteBuddy matcher that decides whether this instrumentation should be applied. Calls
|
* A ByteBuddy matcher that decides whether this instrumentation should be applied. Calls
|
||||||
* generated {@link ReferenceMatcher}: if any mismatch with the passed {@code classLoader} is
|
* generated {@link ReferenceMatcher}: if any mismatch with the passed {@code classLoader} is
|
||||||
|
|
Loading…
Reference in New Issue