diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/BootDelegationInstrumentation.java b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/BootDelegationInstrumentation.java index 74ef07ba249c..f619782f5024 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/BootDelegationInstrumentation.java +++ b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/BootDelegationInstrumentation.java @@ -47,10 +47,7 @@ public class BootDelegationInstrumentation implements TypeInstrumentation { public ElementMatcher typeMatcher() { // just an optimization to exclude common class loaders that are known to delegate to the // bootstrap loader (or happen to _be_ the bootstrap loader) - return not(namedOneOf( - "java.lang.ClassLoader", - "com.ibm.oti.vm.BootstrapClassLoader", - "io.opentelemetry.javaagent.bootstrap.AgentClassLoader")) + return not(namedOneOf("java.lang.ClassLoader", "com.ibm.oti.vm.BootstrapClassLoader")) .and(extendsClass(named("java.lang.ClassLoader"))); } @@ -136,13 +133,14 @@ public static Class onEnter(@Advice.Argument(0) String name) { return null; } - @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onExit( - @Advice.Return(readOnly = false) Class result, - @Advice.Enter Class resultFromBootstrapLoader) { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + @Advice.AssignReturned.ToReturned + public static Class onExit( + @Advice.Return Class result, @Advice.Enter Class resultFromBootstrapLoader) { if (resultFromBootstrapLoader != null) { - result = resultFromBootstrapLoader; + return resultFromBootstrapLoader; } + return result; } } } diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentationModule.java b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentationModule.java index 91fbb3b4baf9..8707d329b222 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentationModule.java +++ b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentationModule.java @@ -25,13 +25,10 @@ public boolean defaultEnabled(ConfigProperties config) { return true; } - @Override - public boolean isIndyModule() { - return false; - } - @Override public boolean isHelperClass(String className) { + // TODO: this can be removed when we drop inlined-advice support + // The advices can directly access this class in the AgentClassLoader with invokedynamic Advice return className.equals("io.opentelemetry.javaagent.tooling.Constants"); } diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/DefineClassInstrumentation.java b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/DefineClassInstrumentation.java index 1e3b63acf1a8..20ca23bb8b0d 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/DefineClassInstrumentation.java +++ b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/DefineClassInstrumentation.java @@ -52,9 +52,15 @@ public static DefineClassContext onEnter( classLoader, className, classBytes, offset, length); } + // TODO: the ToReturned does nothing except for signaling the AdviceTransformer that it must + // not touch this advice + // this is done because we do not want the return values to be wrapped in array types @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Enter DefineClassContext context) { + @Advice.AssignReturned.ToReturned + public static Class onExit( + @Advice.Enter DefineClassContext context, @Advice.Return Class returned) { DefineClassHelper.afterDefineClass(context); + return returned; } } @@ -68,9 +74,15 @@ public static DefineClassContext onEnter( return DefineClassHelper.beforeDefineClass(classLoader, className, classBytes); } + // TODO: the ToReturned does nothing except for signaling the AdviceTransformer that it must + // not touch this advice + // this is done because we do not want the return values to be wrapped in array types @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit(@Advice.Enter DefineClassContext context) { + @Advice.AssignReturned.ToReturned + public static Class onExit( + @Advice.Enter DefineClassContext context, @Advice.Return Class returned) { DefineClassHelper.afterDefineClass(context); + return returned; } } } diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/LoadInjectedClassInstrumentation.java b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/LoadInjectedClassInstrumentation.java index e39f0eef8459..c967eef599d0 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/LoadInjectedClassInstrumentation.java +++ b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/LoadInjectedClassInstrumentation.java @@ -65,11 +65,13 @@ public static Class onEnter( } @Advice.OnMethodExit(onThrowable = Throwable.class) - public static void onExit( - @Advice.Return(readOnly = false) Class result, @Advice.Enter Class loadedClass) { + @Advice.AssignReturned.ToReturned + public static Class onExit( + @Advice.Return Class result, @Advice.Enter Class loadedClass) { if (loadedClass != null) { - result = loadedClass; + return loadedClass; } + return result; } } } diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ResourceInjectionInstrumentation.java b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ResourceInjectionInstrumentation.java index de47454033a8..65076ce645d7 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ResourceInjectionInstrumentation.java +++ b/instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ResourceInjectionInstrumentation.java @@ -61,18 +61,18 @@ public void transform(TypeTransformer transformer) { public static class GetResourceAdvice { @Advice.OnMethodExit(suppress = Throwable.class) - public static void onExit( + @Advice.AssignReturned.ToReturned + public static URL onExit( @Advice.This ClassLoader classLoader, @Advice.Argument(0) String name, - @Advice.Return(readOnly = false) URL resource) { - if (resource != null) { - return; - } - - URL helper = HelperResources.loadOne(classLoader, name); - if (helper != null) { - resource = helper; + @Advice.Return URL resource) { + if (resource == null) { + URL helper = HelperResources.loadOne(classLoader, name); + if (helper != null) { + return helper; + } } + return resource; } } @@ -80,18 +80,18 @@ public static void onExit( public static class GetResourcesAdvice { @Advice.OnMethodExit(suppress = Throwable.class) - public static void onExit( + @Advice.AssignReturned.ToReturned + public static Enumeration onExit( @Advice.This ClassLoader classLoader, @Advice.Argument(0) String name, - @Advice.Return(readOnly = false) Enumeration resources) { + @Advice.Return Enumeration resources) { List helpers = HelperResources.loadAll(classLoader, name); if (helpers.isEmpty()) { - return; + return resources; } if (!resources.hasMoreElements()) { - resources = Collections.enumeration(helpers); - return; + return Collections.enumeration(helpers); } List result = Collections.list(resources); @@ -108,8 +108,7 @@ public static void onExit( result.add(helperUrl); } } - - resources = Collections.enumeration(result); + return Collections.enumeration(result); } } @@ -117,22 +116,22 @@ public static void onExit( public static class GetResourceAsStreamAdvice { @Advice.OnMethodExit(suppress = Throwable.class) - public static void onExit( + @Advice.AssignReturned.ToReturned + public static InputStream onExit( @Advice.This ClassLoader classLoader, @Advice.Argument(0) String name, - @Advice.Return(readOnly = false) InputStream inputStream) { - if (inputStream != null) { - return; - } - - URL helper = HelperResources.loadOne(classLoader, name); - if (helper != null) { - try { - inputStream = helper.openStream(); - } catch (IOException ignored) { - // ClassLoader.getResourceAsStream also ignores io exceptions from opening the stream + @Advice.Return InputStream inputStream) { + if (inputStream == null) { + URL helper = HelperResources.loadOne(classLoader, name); + if (helper != null) { + try { + return helper.openStream(); + } catch (IOException ignored) { + // ClassLoader.getResourceAsStream also ignores io exceptions from opening the stream + } } } + return inputStream; } } } diff --git a/javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/IndyBootstrapDispatcher.java b/javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/IndyBootstrapDispatcher.java index efc6e4730ec7..39693200d65f 100644 --- a/javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/IndyBootstrapDispatcher.java +++ b/javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/IndyBootstrapDispatcher.java @@ -54,8 +54,7 @@ public static CallSite bootstrap( return callSite; } - // package visibility for testing - static MethodHandle generateNoopMethodHandle(MethodType methodType) { + public static MethodHandle generateNoopMethodHandle(MethodType methodType) { Class returnType = methodType.returnType(); MethodHandle noopNoArg; if (returnType == void.class) { diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceBootstrapState.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceBootstrapState.java new file mode 100644 index 000000000000..00e4759aa1b8 --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceBootstrapState.java @@ -0,0 +1,152 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.instrumentation.indy; + +import java.lang.invoke.MutableCallSite; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; +import javax.annotation.Nullable; + +class AdviceBootstrapState implements AutoCloseable { + + private static final ThreadLocal> stateForCurrentThread = + ThreadLocal.withInitial(HashMap::new); + + private final Key key; + private int recursionDepth; + @Nullable private MutableCallSite nestedCallSite; + + /** + * We have to eagerly initialize to not cause a lambda construction during {@link #enter(Class, + * String, String, String, String)}. + */ + private static final Function CONSTRUCTOR = AdviceBootstrapState::new; + + private AdviceBootstrapState(Key key) { + this.key = key; + // enter will increment it by one, so 0 is the value for non-recursive calls + recursionDepth = -1; + } + + static void initialize() { + // Eager initialize everything because we could run into recursions doing this during advice + // bootstrapping + stateForCurrentThread.get(); + stateForCurrentThread.remove(); + try { + Class.forName(Key.class.getName()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } + } + + static AdviceBootstrapState enter( + Class instrumentedClass, + String moduleClassName, + String adviceClassName, + String adviceMethodName, + String adviceMethodDescriptor) { + Key key = + new Key( + instrumentedClass, + moduleClassName, + adviceClassName, + adviceMethodName, + adviceMethodDescriptor); + AdviceBootstrapState state = stateForCurrentThread.get().computeIfAbsent(key, CONSTRUCTOR); + state.recursionDepth++; + return state; + } + + public boolean isNestedInvocation() { + return recursionDepth > 0; + } + + public MutableCallSite getOrInitMutableCallSite(Supplier initializer) { + if (nestedCallSite == null) { + nestedCallSite = initializer.get(); + } + return nestedCallSite; + } + + public void initMutableCallSite(MutableCallSite mutableCallSite) { + if (nestedCallSite != null) { + throw new IllegalStateException("callsite has already been initialized"); + } + nestedCallSite = mutableCallSite; + } + + @Nullable + public MutableCallSite getMutableCallSite() { + return nestedCallSite; + } + + @Override + public void close() { + if (recursionDepth == 0) { + Map stateMap = stateForCurrentThread.get(); + stateMap.remove(key); + if (stateMap.isEmpty()) { + // Do not leave an empty map dangling as thread local + stateForCurrentThread.remove(); + } + } else { + recursionDepth--; + } + } + + /** Key uniquely identifying a single invokedynamic instruction inserted for an advice */ + private static class Key { + + private final Class instrumentedClass; + private final String moduleClassName; + private final String adviceClassName; + private final String adviceMethodName; + private final String adviceMethodDescriptor; + + private Key( + Class instrumentedClass, + String moduleClassName, + String adviceClassName, + String adviceMethodName, + String adviceMethodDescriptor) { + this.instrumentedClass = instrumentedClass; + this.moduleClassName = moduleClassName; + this.adviceClassName = adviceClassName; + this.adviceMethodName = adviceMethodName; + this.adviceMethodDescriptor = adviceMethodDescriptor; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || !(o instanceof Key)) { + return false; + } + + Key that = (Key) o; + return instrumentedClass.equals(that.instrumentedClass) + && moduleClassName.equals(that.moduleClassName) + && adviceClassName.equals(that.adviceClassName) + && adviceMethodName.equals(that.adviceMethodName) + && adviceMethodDescriptor.equals(that.adviceMethodDescriptor); + } + + @Override + public int hashCode() { + int result = instrumentedClass.hashCode(); + result = 31 * result + moduleClassName.hashCode(); + result = 31 * result + adviceClassName.hashCode(); + result = 31 * result + adviceMethodName.hashCode(); + result = 31 * result + adviceMethodDescriptor.hashCode(); + return result; + } + } +} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceTransformer.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceTransformer.java index ac1f46a99e3a..aab45a387921 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceTransformer.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceTransformer.java @@ -67,6 +67,9 @@ static byte[] transform(byte[] bytes) { })); TransformationContext context = new TransformationContext(); + if (justDelegateAdvice) { + context.disableReturnTypeChange(); + } ClassVisitor cv = new ClassVisitor(AsmApi.VERSION, cw) { diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyBootstrap.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyBootstrap.java index 3ec6d531138d..bc8536fe5629 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyBootstrap.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyBootstrap.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.tooling.instrumentation.indy; -import io.opentelemetry.javaagent.bootstrap.CallDepth; import io.opentelemetry.javaagent.bootstrap.IndyBootstrapDispatcher; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import java.lang.invoke.CallSite; @@ -13,6 +12,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; import java.lang.reflect.Method; import java.security.PrivilegedAction; import java.util.Arrays; @@ -84,7 +84,7 @@ public class IndyBootstrap { MethodType bootstrapMethodType = MethodType.methodType( - ConstantCallSite.class, + CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, @@ -92,6 +92,8 @@ public class IndyBootstrap { IndyBootstrapDispatcher.init( MethodHandles.lookup().findStatic(IndyBootstrap.class, "bootstrap", bootstrapMethodType)); + + AdviceBootstrapState.initialize(); } catch (Exception e) { throw new IllegalStateException(e); } @@ -105,7 +107,7 @@ public static Method getIndyBootstrapMethod() { @Nullable @SuppressWarnings({"unused", "removal"}) // SecurityManager and AccessController are deprecated - private static ConstantCallSite bootstrap( + private static CallSite bootstrap( MethodHandles.Lookup lookup, String adviceMethodName, MethodType adviceMethodType, @@ -118,11 +120,11 @@ private static ConstantCallSite bootstrap( // callsite resolution needs privileged access to call Class#getClassLoader() and // MethodHandles$Lookup#findStatic return java.security.AccessController.doPrivileged( - (PrivilegedAction) + (PrivilegedAction) () -> internalBootstrap(lookup, adviceMethodName, adviceMethodType, args)); } - private static ConstantCallSite internalBootstrap( + private static CallSite internalBootstrap( MethodHandles.Lookup lookup, String adviceMethodName, MethodType adviceMethodType, @@ -157,7 +159,7 @@ private static ConstantCallSite internalBootstrap( } } - private static ConstantCallSite bootstrapAdvice( + private static CallSite bootstrapAdvice( MethodHandles.Lookup lookup, String adviceMethodName, MethodType invokedynamicMethodType, @@ -165,17 +167,25 @@ private static ConstantCallSite bootstrapAdvice( String adviceMethodDescriptor, String adviceClassName) throws NoSuchMethodException, IllegalAccessException, ClassNotFoundException { - CallDepth callDepth = CallDepth.forClass(IndyBootstrap.class); - try { - if (callDepth.getAndIncrement() > 0) { + try (AdviceBootstrapState nestedState = + AdviceBootstrapState.enter( + lookup.lookupClass(), + moduleClassName, + adviceClassName, + adviceMethodName, + adviceMethodDescriptor)) { + if (nestedState.isNestedInvocation()) { // avoid re-entrancy and stack overflow errors, which may happen when bootstrapping an // instrumentation that also gets triggered during the bootstrap // for example, adding correlation ids to the thread context when executing logger.debug. - logger.log( - Level.WARNING, - "Nested instrumented invokedynamic instruction linkage detected", - new Throwable()); - return null; + MutableCallSite mutableCallSite = nestedState.getMutableCallSite(); + if (mutableCallSite == null) { + mutableCallSite = + new MutableCallSite( + IndyBootstrapDispatcher.generateNoopMethodHandle(invokedynamicMethodType)); + nestedState.initMutableCallSite(mutableCallSite); + } + return mutableCallSite; } InstrumentationModuleClassLoader instrumentationClassloader = @@ -193,9 +203,21 @@ private static ConstantCallSite bootstrapAdvice( .getLookup() .findStatic(adviceClass, adviceMethodName, actualAdviceMethodType) .asType(invokedynamicMethodType); - return new ConstantCallSite(methodHandle); - } finally { - callDepth.decrementAndGet(); + + MutableCallSite nestedBootstrapCallSite = nestedState.getMutableCallSite(); + if (nestedBootstrapCallSite != null) { + // There have been nested bootstrapping attempts + // Update the callsite of those to run the actual instrumentation + logger.log( + Level.FINE, + "Fixing nested instrumentation invokedynamic instruction bootstrapping for instrumented class {0} and advice {1}.{2}, the instrumentation should be active now", + new Object[] {lookup.lookupClass().getName(), adviceClassName, adviceMethodName}); + nestedBootstrapCallSite.setTarget(methodHandle); + MutableCallSite.syncAll(new MutableCallSite[] {nestedBootstrapCallSite}); + return nestedBootstrapCallSite; + } else { + return new ConstantCallSite(methodHandle); + } } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/InstrumentationModuleClassLoader.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/InstrumentationModuleClassLoader.java index b4d2477dd57e..5d5a868e21b4 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/InstrumentationModuleClassLoader.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/InstrumentationModuleClassLoader.java @@ -196,6 +196,15 @@ public void applyTransformer(AgentBuilder.Transformer transformer) {} public static final Map bytecodeOverride = new ConcurrentHashMap<>(); + @Override + public Class loadClass(String name) throws ClassNotFoundException { + // We explicitly override loadClass from ClassLoader to ensure + // that loadClass is properly excluded from our internal ClassLoader Instrumentations + // (e.g. LoadInjectedClassInstrumentation, BooDelegationInstrumentation) + // Otherwise this will cause recursion in invokedynamic linkage + return loadClass(name, false); + } + @Override @SuppressWarnings("removal") // AccessController is deprecated for removal protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { @@ -317,12 +326,23 @@ private BytecodeWithUrl getInjectedClass(String name) { } private Class defineClassWithPackage(String name, byte[] bytecode) { - int lastDotIndex = name.lastIndexOf('.'); - if (lastDotIndex != -1) { - String packageName = name.substring(0, lastDotIndex); - safeDefinePackage(packageName); + try { + int lastDotIndex = name.lastIndexOf('.'); + if (lastDotIndex != -1) { + String packageName = name.substring(0, lastDotIndex); + safeDefinePackage(packageName); + } + return defineClass(name, bytecode, 0, bytecode.length, PROTECTION_DOMAIN); + } catch (LinkageError error) { + // Precaution against linkage error due to nested instrumentations happening + // it might be possible that e.g. an advice class has already been defined + // during an instrumentation of defineClass + Class clazz = findLoadedClass(name); + if (clazz != null) { + return clazz; + } + throw error; } - return defineClass(name, bytecode, 0, bytecode.length, PROTECTION_DOMAIN); } private void safeDefinePackage(String packageName) { diff --git a/testing-common/integration-tests/build.gradle.kts b/testing-common/integration-tests/build.gradle.kts index 54283321482a..3379dcfab84b 100644 --- a/testing-common/integration-tests/build.gradle.kts +++ b/testing-common/integration-tests/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { testCompileOnly(project(":instrumentation-api")) testCompileOnly(project(":javaagent-tooling")) + testCompileOnly(project(":javaagent-bootstrap")) testCompileOnly(project(":javaagent-extension-api")) testCompileOnly(project(":muzzle")) diff --git a/testing-common/integration-tests/src/test/groovy/AgentInstrumentationSpecificationTest.groovy b/testing-common/integration-tests/src/test/groovy/AgentInstrumentationSpecificationTest.groovy index 530221e4553f..e6af2be22ddd 100644 --- a/testing-common/integration-tests/src/test/groovy/AgentInstrumentationSpecificationTest.groovy +++ b/testing-common/integration-tests/src/test/groovy/AgentInstrumentationSpecificationTest.groovy @@ -6,7 +6,7 @@ import com.google.common.reflect.ClassPath import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification import io.opentelemetry.instrumentation.test.utils.ClasspathUtils -import io.opentelemetry.javaagent.tooling.Constants +import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder import org.slf4j.LoggerFactory import java.util.concurrent.TimeoutException @@ -17,12 +17,14 @@ import java.util.concurrent.TimeoutException class AgentInstrumentationSpecificationTest extends AgentInstrumentationSpecification { private static final ClassLoader BOOTSTRAP_CLASSLOADER = null + public static final List BOOTSTRAP_PACKAGE_PREFIXES = BootstrapPackagePrefixesHolder.getBoostrapPackagePrefixes() + def "classpath setup"() { setup: final List bootstrapClassesIncorrectlyLoaded = [] for (ClassPath.ClassInfo info : getTestClasspath().getAllClasses()) { - for (int i = 0; i < Constants.BOOTSTRAP_PACKAGE_PREFIXES.size(); ++i) { - if (info.getName().startsWith(Constants.BOOTSTRAP_PACKAGE_PREFIXES[i])) { + for (int i = 0; i < BOOTSTRAP_PACKAGE_PREFIXES.size(); ++i) { + if (info.getName().startsWith(BOOTSTRAP_PACKAGE_PREFIXES[i])) { Class bootstrapClass = Class.forName(info.getName()) def loader try {