Don't call Thread#setContextClassLoader()
Related to
Unfortunately it doesn't fix the aforementioned issue; while the CL used
is no longer the agent classloader, gauge collection still throws that
error.
Still, I think this is a good change that removes one source of agent's
CL leaking into application runtime.
MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
@@ -19,7 +19,6 @@ import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil;
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;
import io.opentelemetry.javaagent.bootstrap.AgentClassLoader;
-import io.opentelemetry.javaagent.bootstrap.AgentInitializer;
import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder;
import io.opentelemetry.javaagent.bootstrap.ClassFileTransformerHolder;
import io.opentelemetry.javaagent.bootstrap.DefineClassHelper;
@@ -78,7 +77,7 @@ public class AgentInstaller {
private static final Map<String, List<Runnable>> CLASS_LOAD_CALLBACKS = new HashMap<>();
- public static void installBytebuddyAgent(Instrumentation inst) {
+ public static void installBytebuddyAgent(Instrumentation inst, ClassLoader extensionClassLoader) {
addByteBuddyRawSetting();
Integer strictContextStressorMillis = Integer.getInteger(STRICT_CONTEXT_STRESSOR_MILLIS);
@@ -90,34 +89,37 @@ public class AgentInstaller {
logVersionInfo();
if (ConfigPropertiesUtil.getBoolean(JAVAAGENT_ENABLED_CONFIG, true)) {
setupUnsafe(inst);
- List<AgentListener> agentListeners = loadOrdered(AgentListener.class);
- installBytebuddyAgent(inst, agentListeners);
+ List<AgentListener> agentListeners = loadOrdered(AgentListener.class, extensionClassLoader);
+ installBytebuddyAgent(inst, extensionClassLoader, agentListeners);
} else {
logger.fine("Tracing is disabled, not installing instrumentations.");
}
}
private static void installBytebuddyAgent(
- Instrumentation inst, Iterable<AgentListener> agentListeners) {
+ Instrumentation inst,
+ ClassLoader extensionClassLoader,
+ Iterable<AgentListener> agentListeners) {
WeakRefAsyncOperationEndStrategies.initialize();
- EmbeddedInstrumentationProperties.setPropertiesLoader(
- AgentInitializer.getExtensionsClassLoader());
+ EmbeddedInstrumentationProperties.setPropertiesLoader(extensionClassLoader);
setDefineClassHandler();
// If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not
// called
- AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = installOpenTelemetrySdk();
+ AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
+ installOpenTelemetrySdk(extensionClassLoader);
ConfigProperties sdkConfig = autoConfiguredSdk.getConfig();
InstrumentationConfig.internalInitializeConfig(new ConfigPropertiesBridge(sdkConfig));
copyNecessaryConfigToSystemProperties(sdkConfig);
- setBootstrapPackages(sdkConfig);
+ setBootstrapPackages(sdkConfig, extensionClassLoader);
- for (BeforeAgentListener agentListener : loadOrdered(BeforeAgentListener.class)) {
+ for (BeforeAgentListener agentListener :
+ loadOrdered(BeforeAgentListener.class, extensionClassLoader)) {
agentListener.beforeAgent(autoConfiguredSdk);
}
@@ -140,7 +142,7 @@ public class AgentInstaller {
agentBuilder = agentBuilder.with(new ExposeAgentBootstrapListener(inst));
}
- agentBuilder = configureIgnoredTypes(sdkConfig, agentBuilder);
+ agentBuilder = configureIgnoredTypes(sdkConfig, extensionClassLoader, agentBuilder);
if (AgentConfig.isDebugModeEnabled(sdkConfig)) {
agentBuilder =
@@ -152,7 +154,7 @@ public class AgentInstaller {
}
int numberOfLoadedExtensions = 0;
- for (AgentExtension agentExtension : loadOrdered(AgentExtension.class)) {
+ for (AgentExtension agentExtension : loadOrdered(AgentExtension.class, extensionClassLoader)) {
if (logger.isLoggable(FINE)) {
logger.log(
FINE,
@@ -196,9 +198,11 @@ public class AgentInstaller {
}
}
- private static void setBootstrapPackages(ConfigProperties config) {
+ private static void setBootstrapPackages(
+ ConfigProperties config, ClassLoader extensionClassLoader) {
BootstrapPackagesBuilderImpl builder = new BootstrapPackagesBuilderImpl();
- for (BootstrapPackagesConfigurer configurer : load(BootstrapPackagesConfigurer.class)) {
+ for (BootstrapPackagesConfigurer configurer :
+ load(BootstrapPackagesConfigurer.class, extensionClassLoader)) {
configurer.configure(builder, config);
}
BootstrapPackagePrefixesHolder.setBoostrapPackagePrefixes(builder.build());
@@ -209,9 +213,10 @@ public class AgentInstaller {
}
private static AgentBuilder configureIgnoredTypes(
- ConfigProperties config, AgentBuilder agentBuilder) {
+ ConfigProperties config, ClassLoader extensionClassLoader, AgentBuilder agentBuilder) {
IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl();
- for (IgnoredTypesConfigurer configurer : loadOrdered(IgnoredTypesConfigurer.class)) {
+ for (IgnoredTypesConfigurer configurer :
+ loadOrdered(IgnoredTypesConfigurer.class, extensionClassLoader)) {
configurer.configure(builder, config);
}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentStarterImpl.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentStarterImpl.java
@@ -62,18 +62,9 @@ public class AgentStarterImpl implements AgentStarter {
@Override
public void start() {
extensionClassLoader = createExtensionClassLoader(getClass().getClassLoader(), javaagentFile);
- ClassLoader savedContextClassLoader = Thread.currentThread().getContextClassLoader();
- try {
- Thread.currentThread().setContextClassLoader(extensionClassLoader);
- internalStart();
- } finally {
- Thread.currentThread().setContextClassLoader(savedContextClassLoader);
- }
- }
- private void internalStart() {
Iterator<LoggingCustomizer> loggingCustomizers =
- ServiceLoader.load(LoggingCustomizer.class).iterator();
+ ServiceLoader.load(LoggingCustomizer.class, extensionClassLoader).iterator();
LoggingCustomizer loggingCustomizer;
if (loggingCustomizers.hasNext()) {
loggingCustomizer = loggingCustomizers.next();
@@ -84,7 +75,7 @@ public class AgentStarterImpl implements AgentStarter {
Throwable startupError = null;
try {
loggingCustomizer.init();
- AgentInstaller.installBytebuddyAgent(instrumentation);
+ AgentInstaller.installBytebuddyAgent(instrumentation, extensionClassLoader);
WeakConcurrentMapCleaner.start();
} catch (Throwable t) {
// this is logged below and not rethrown to avoid logging it twice

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java
package io.opentelemetry.javaagent.tooling;
-import io.opentelemetry.javaagent.bootstrap.AgentInitializer;
import io.opentelemetry.javaagent.bootstrap.OpenTelemetrySdkAccess;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
-import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.common.CompletableResultCode;
import java.util.Arrays;
@@ -21,17 +19,14 @@ public final class OpenTelemetryInstaller {
*
* @return the {@link AutoConfiguredOpenTelemetrySdk}
*/
- public static AutoConfiguredOpenTelemetrySdk installOpenTelemetrySdk() {
- AutoConfiguredOpenTelemetrySdkBuilder builder =
- AutoConfiguredOpenTelemetrySdk.builder().setResultAsGlobal(true);
-
- ClassLoader classLoader = AgentInitializer.getExtensionsClassLoader();
- if (classLoader != null) {
- // May be null in unit tests.
- builder.setServiceClassLoader(classLoader);
- }
-
- AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = builder.build();
+ public static AutoConfiguredOpenTelemetrySdk installOpenTelemetrySdk(
+ ClassLoader extensionClassLoader) {
+
+ AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
+ AutoConfiguredOpenTelemetrySdk.builder()
+ .setResultAsGlobal(true)
+ .setServiceClassLoader(extensionClassLoader)
+ .build();
OpenTelemetrySdk sdk = autoConfiguredSdk.getOpenTelemetrySdk();
OpenTelemetrySdkAccess.internalSetForceFlush(

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/SafeServiceLoader.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/SafeServiceLoader.java
@@ -30,9 +30,9 @@ public final class SafeServiceLoader {
*/
// Because we want to catch exception per iteration
@SuppressWarnings("ForEachIterable")
- public static <T> List<T> load(Class<T> serviceClass) {
+ public static <T> List<T> load(Class<T> serviceClass, ClassLoader classLoader) {
List<T> result = new ArrayList<>();
- ServiceLoader<T> services = ServiceLoader.load(serviceClass);
+ ServiceLoader<T> services = ServiceLoader.load(serviceClass, classLoader);
for (Iterator<T> iterator = new SafeIterator<>(services.iterator()); iterator.hasNext(); ) {
T service = iterator.next();
if (service != null) {
@@ -43,11 +43,12 @@ public final class SafeServiceLoader {
}
/**
- * Same as {@link #load(Class)}, but also orders the returned implementations by comparing their
- * {@link Ordered#order()}.
+ * Same as {@link #load(Class, ClassLoader)}, but also orders the returned implementations by
+ * comparing their {@link Ordered#order()}.
*/
- public static <T extends Ordered> List<T> loadOrdered(Class<T> serviceClass) {
- List<T> result = load(serviceClass);
+ public static <T extends Ordered> List<T> loadOrdered(
+ Class<T> serviceClass, ClassLoader classLoader) {
+ List<T> result = load(serviceClass, classLoader);
result.sort(Comparator.comparing(Ordered::order));
return result;
}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/InstrumentationLoader.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/InstrumentationLoader.java
@@ -13,6 +13,7 @@ import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.AgentExtension;
+import io.opentelemetry.javaagent.tooling.Utils;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import java.util.logging.Logger;
import net.bytebuddy.agent.builder.AgentBuilder;
@@ -27,7 +28,8 @@ public class InstrumentationLoader implements AgentExtension {
@Override
public AgentBuilder extend(AgentBuilder agentBuilder, ConfigProperties config) {
int numberOfLoadedModules = 0;
- for (InstrumentationModule instrumentationModule : loadOrdered(InstrumentationModule.class)) {
+ for (InstrumentationModule instrumentationModule :
+ loadOrdered(InstrumentationModule.class, Utils.getExtensionsClassLoader())) {
if (logger.isLoggable(FINE)) {
logger.log(
FINE,

MODIFY
javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/test/HelperInjectionTest.groovy
javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/test/HelperInjectionTest.groovy
@@ -61,7 +61,7 @@ class HelperInjectionTest extends Specification {
def "helpers injected on bootstrap classloader"() {
setup:
ByteBuddyAgent.install()
- AgentInstaller.installBytebuddyAgent(ByteBuddyAgent.getInstrumentation())
+ AgentInstaller.installBytebuddyAgent(ByteBuddyAgent.getInstrumentation(), this.class.classLoader)
String helperClassName = HelperInjectionTest.getPackage().getName() + '.HelperClass'
HelperInjector injector = new HelperInjector("test", [helperClassName], [], this.class.classLoader, ByteBuddyAgent.getInstrumentation())
URLClassLoader bootstrapChild = new URLClassLoader(new URL[0], (ClassLoader) null)

MODIFY
javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.groovy
javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.groovy
@@ -24,7 +24,7 @@ class OpenTelemetryInstallerTest extends Specification {
def "should initialize GlobalOpenTelemetry"() {
when:
- def otelInstaller = OpenTelemetryInstaller.installOpenTelemetrySdk()
+ def otelInstaller = OpenTelemetryInstaller.installOpenTelemetrySdk(OpenTelemetryInstaller.classLoader)
then:
otelInstaller != null

MODIFY
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationFileLoaderTest.java
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationFileLoaderTest.java
@@ -46,7 +46,7 @@ class ConfigurationFileLoaderTest {
// when
AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
- OpenTelemetryInstaller.installOpenTelemetrySdk();
+ OpenTelemetryInstaller.installOpenTelemetrySdk(this.getClass().getClassLoader());
// then
assertThat(autoConfiguredSdk.getConfig().getString("custom.key")).isEqualTo("42");

MODIFY
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/AgentTooling.java
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/AgentTooling.java
@@ -32,7 +32,8 @@ public final class AgentTooling {
private static ClassLoader getBootstrapProxy() {
Iterator<BootstrapProxyProvider> iterator =
- ServiceLoader.load(BootstrapProxyProvider.class).iterator();
+ ServiceLoader.load(BootstrapProxyProvider.class, AgentTooling.class.getClassLoader())
+ .iterator();
if (iterator.hasNext()) {
BootstrapProxyProvider bootstrapProxyProvider = iterator.next();
return bootstrapProxyProvider.getBootstrapProxy();

MODIFY
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ClassLoaderMatcher.java
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ClassLoaderMatcher.java
@@ -33,7 +33,7 @@ public class ClassLoaderMatcher {
public static Map<String, List<Mismatch>> matchesAll(
ClassLoader classLoader, boolean injectHelpers, Set<String> excludedInstrumentationNames) {
Map<String, List<Mismatch>> result = new HashMap<>();
- ServiceLoader.load(InstrumentationModule.class)
+ ServiceLoader.load(InstrumentationModule.class, ClassLoaderMatcher.class.getClassLoader())
.forEach(
module -> {
if (module.instrumentationNames().stream()

MODIFY
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ReferencesPrinter.java
muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ReferencesPrinter.java
@@ -26,7 +26,7 @@ public final class ReferencesPrinter {
*/
public static void printMuzzleReferences() {
for (InstrumentationModule instrumentationModule :
- ServiceLoader.load(InstrumentationModule.class)) {
+ ServiceLoader.load(InstrumentationModule.class, ReferencesPrinter.class.getClassLoader())) {
try {
System.out.println(instrumentationModule.getClass().getName());
for (ClassRef ref :

MODIFY
testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/bytebuddy/TestAgentListener.java
testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/bytebuddy/TestAgentListener.java
@@ -10,6 +10,7 @@ import static java.util.logging.Level.SEVERE;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
import io.opentelemetry.javaagent.tooling.EmptyConfigProperties;
import io.opentelemetry.javaagent.tooling.SafeServiceLoader;
+import io.opentelemetry.javaagent.tooling.Utils;
import io.opentelemetry.javaagent.tooling.ignore.AdditionalLibraryIgnoredTypesConfigurer;
import io.opentelemetry.javaagent.tooling.ignore.GlobalIgnoredTypesConfigurer;
import io.opentelemetry.javaagent.tooling.ignore.IgnoreAllow;
@@ -51,7 +52,8 @@ public class TestAgentListener implements AgentBuilder.Listener {
private static Trie<IgnoreAllow> buildOtherConfiguredIgnores() {
IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl();
for (IgnoredTypesConfigurer configurer :
- SafeServiceLoader.loadOrdered(IgnoredTypesConfigurer.class)) {
+ SafeServiceLoader.loadOrdered(
+ IgnoredTypesConfigurer.class, Utils.getExtensionsClassLoader())) {
// skip built-in agent ignores
if (configurer instanceof AdditionalLibraryIgnoredTypesConfigurer
|| configurer instanceof GlobalIgnoredTypesConfigurer) {

Don't call Thread#setContextClassLoader() (#7391)

Related to #7220

Unfortunately it doesn't fix the aforementioned issue; while the CL used
is no longer the agent classloader, gauge collection still throws that
error.
Still, I think this is a good change that removes one source of agent's
CL leaking into application runtime.