Add SPI to configure additional bootstrap package prefixes
This feature is useful when a large set of custom instrumentations is
using common classes from a custom package.
ADD
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BootstrapPackagePrefixesHolder.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.api.internal;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * {@link BootstrapPackagePrefixesHolder} is an utility class that holds package prefixes. The
+ * classes from these packages are pushed to the bootstrap classloader.
+ *
+ * <p>The prefixes are loaded by {@code AgentInstaller} and consumed by classloader instrumentation.
+ * The instrumentation does not have access to the installer, therefore this utility class is used
+ * to share package prefixes.
+ */
+public class BootstrapPackagePrefixesHolder {
+
+ private static volatile List<String> BOOSTRAP_PACKAGE_PREFIXES;
+
+ public static List<String> getBoostrapPackagePrefixes() {
+ return BOOSTRAP_PACKAGE_PREFIXES;
+ }
+
+ public static void setBoostrapPackagePrefixes(List<String> prefixes) {
+ if (BOOSTRAP_PACKAGE_PREFIXES != null) {
+ // Only possible by misuse of this API, just ignore.
+ return;
+ }
+ BOOSTRAP_PACKAGE_PREFIXES = Collections.unmodifiableList(prefixes);
+ }
+}

MODIFY
instrumentation/java-classloader/src/main/java/io/opentelemetry/javaagent/instrumentation/javaclassloader/ClassLoaderInstrumentation.java
instrumentation/java-classloader/src/main/java/io/opentelemetry/javaagent/instrumentation/javaclassloader/ClassLoaderInstrumentation.java
@@ -18,6 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
+import io.opentelemetry.instrumentation.api.internal.BootstrapPackagePrefixesHolder;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.tooling.Constants;
import io.opentelemetry.javaagent.tooling.Instrumenter;
@@ -88,7 +89,7 @@ public final class ClassLoaderInstrumentation extends Instrumenter.Default {
return null;
}
try {
- for (String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) {
+ for (String prefix : BootstrapPackagePrefixesHolder.getBoostrapPackagePrefixes()) {
if (name.startsWith(prefix)) {
try {
return Class.forName(name, false, null);

ADD
javaagent-spi/src/main/java/io/opentelemetry/javaagent/spi/BootstrapPackagesProvider.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.spi;
+
+import java.util.List;
+
+/**
+ * A service provider to allow adding classes from specified package prefixes to the bootstrap
+ * classloader. The classes in the bootstrap classloader are available to all instrumentations. This
+ * is useful if large number of custom instrumentations are using functionality from common
+ * packages.
+ */
+public interface BootstrapPackagesProvider {
+
+ /**
+ * Classes from returned package prefixes will be available in the bootstrap classloader.
+ *
+ * @return package prefixes.
+ */
+ List<String> getPackagePrefixes();
+}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
@@ -14,14 +14,17 @@ import static net.bytebuddy.matcher.ElementMatchers.none;
import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.instrumentation.api.internal.BootstrapPackagePrefixesHolder;
import io.opentelemetry.javaagent.instrumentation.api.OpenTelemetrySdkAccess;
import io.opentelemetry.javaagent.instrumentation.api.OpenTelemetrySdkAccess.ForceFlusher;
import io.opentelemetry.javaagent.instrumentation.api.SafeServiceLoader;
+import io.opentelemetry.javaagent.spi.BootstrapPackagesProvider;
import io.opentelemetry.javaagent.tooling.config.ConfigInitializer;
import io.opentelemetry.javaagent.tooling.context.FieldBackedProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -52,6 +55,7 @@ public class AgentInstaller {
}
static {
+ BootstrapPackagePrefixesHolder.setBoostrapPackagePrefixes(loadBootstrapPackagePrefixes());
// WeakMap is used by other classes below, so we need to register the provider first.
AgentTooling.registerWeakMapProvider();
// this needs to be done as early as possible - before the first Config.get() call
@@ -207,6 +211,23 @@ public class AgentInstaller {
return matcher;
}
+ private static List<String> loadBootstrapPackagePrefixes() {
+ List<String> bootstrapPackages =
+ new ArrayList<>(Arrays.asList(Constants.BOOTSTRAP_PACKAGE_PREFIXES));
+ Iterable<BootstrapPackagesProvider> bootstrapPackagesProviders =
+ SafeServiceLoader.load(
+ BootstrapPackagesProvider.class, AgentInstaller.class.getClassLoader());
+ for (BootstrapPackagesProvider provider : bootstrapPackagesProviders) {
+ List<String> packagePrefixes = provider.getPackagePrefixes();
+ log.debug(
+ "Loaded bootstrap package prefixes from {}: {}",
+ provider.getClass().getName(),
+ packagePrefixes);
+ bootstrapPackages.addAll(packagePrefixes);
+ }
+ return bootstrapPackages;
+ }
+
static class RedefinitionLoggingListener implements AgentBuilder.RedefinitionStrategy.Listener {
private static final Logger log = LoggerFactory.getLogger(RedefinitionLoggingListener.class);

Add SPI to configure additional bootstrap package prefixes (#1380)

This feature is useful when a large set of custom instrumentations is
using common classes from a custom package.