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.
This commit is contained in:
parent
15e0b2ff32
commit
f29763d6ef
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
|
import io.opentelemetry.instrumentation.api.internal.BootstrapPackagePrefixesHolder;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
|
||||||
import io.opentelemetry.javaagent.tooling.Constants;
|
import io.opentelemetry.javaagent.tooling.Constants;
|
||||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||||
|
@ -88,7 +89,7 @@ public final class ClassLoaderInstrumentation extends Instrumenter.Default {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) {
|
for (String prefix : BootstrapPackagePrefixesHolder.getBoostrapPackagePrefixes()) {
|
||||||
if (name.startsWith(prefix)) {
|
if (name.startsWith(prefix)) {
|
||||||
try {
|
try {
|
||||||
return Class.forName(name, false, null);
|
return Class.forName(name, false, null);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
|
@ -14,14 +14,17 @@ import static net.bytebuddy.matcher.ElementMatchers.none;
|
||||||
|
|
||||||
import io.opentelemetry.OpenTelemetry;
|
import io.opentelemetry.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.api.config.Config;
|
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;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.OpenTelemetrySdkAccess.ForceFlusher;
|
import io.opentelemetry.javaagent.instrumentation.api.OpenTelemetrySdkAccess.ForceFlusher;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.SafeServiceLoader;
|
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.config.ConfigInitializer;
|
||||||
import io.opentelemetry.javaagent.tooling.context.FieldBackedProvider;
|
import io.opentelemetry.javaagent.tooling.context.FieldBackedProvider;
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||||
import java.lang.instrument.Instrumentation;
|
import java.lang.instrument.Instrumentation;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -52,6 +55,7 @@ public class AgentInstaller {
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
BootstrapPackagePrefixesHolder.setBoostrapPackagePrefixes(loadBootstrapPackagePrefixes());
|
||||||
// WeakMap is used by other classes below, so we need to register the provider first.
|
// WeakMap is used by other classes below, so we need to register the provider first.
|
||||||
AgentTooling.registerWeakMapProvider();
|
AgentTooling.registerWeakMapProvider();
|
||||||
// this needs to be done as early as possible - before the first Config.get() call
|
// this needs to be done as early as possible - before the first Config.get() call
|
||||||
|
@ -207,6 +211,23 @@ public class AgentInstaller {
|
||||||
return matcher;
|
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 {
|
static class RedefinitionLoggingListener implements AgentBuilder.RedefinitionStrategy.Listener {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RedefinitionLoggingListener.class);
|
private static final Logger log = LoggerFactory.getLogger(RedefinitionLoggingListener.class);
|
||||||
|
|
Loading…
Reference in New Issue