diff --git a/benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java b/benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java index 52edfe4d8f..5b279569ef 100644 --- a/benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java +++ b/benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java @@ -6,7 +6,6 @@ package io.opentelemetry.benchmark; import io.opentelemetry.instrumentation.api.config.Config; -import io.opentelemetry.javaagent.tooling.AgentInstaller; import io.opentelemetry.javaagent.tooling.ignore.AdditionalLibraryIgnoredTypesConfigurer; import io.opentelemetry.javaagent.tooling.ignore.IgnoredTypesBuilderImpl; import io.opentelemetry.javaagent.tooling.ignore.IgnoredTypesMatcher; @@ -38,9 +37,7 @@ public class IgnoredTypesMatcherBenchmark { static { IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl(); new AdditionalLibraryIgnoredTypesConfigurer().configure(Config.get(), builder); - ignoredTypesMatcher = - new IgnoredTypesMatcher( - new AgentInstaller.NoopIgnoreMatcherProvider(), builder.buildIgnoredTypesTrie()); + ignoredTypesMatcher = new IgnoredTypesMatcher(builder.buildIgnoredTypesTrie()); } @Benchmark diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/spi/IgnoreMatcherProvider.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/spi/IgnoreMatcherProvider.java deleted file mode 100644 index 04a853eff6..0000000000 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/spi/IgnoreMatcherProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.spi; - -import net.bytebuddy.description.type.TypeDescription; - -/** - * {@link IgnoreMatcherProvider} can be used to ignore (or allow) types (e.g. classes or - * classloaders) from being instrumented. OpenTelemetry agent by default ignores specific set of - * classes (e.g. {@code org.gradle.*}) and classloaders. This is mainly done to improve startup - * time, but also to explicitly disable instrumentation of a specific types (e.g. other agents). An - * implementation of this class can be used to override this behaviour. - * - *

This is a service provider interface that requires implementations to be registered in {@code - * META-INF/services} folder. Only a single implementation of this SPI can be provided. - * - * @deprecated Please use {@link io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer} - * instead. - */ -@Deprecated -public interface IgnoreMatcherProvider { - - /** - * Whether to ignore (or allow) type. This method is called for every class, therefore the - * implementation has to be as efficient as possible. - * - * @param target a class. - * @return the result of the ignore evaluation. - */ - Result type(TypeDescription target); - - /** - * Whether to ignore (or allow) classloader. This method is called for every classloader, - * therefore the implementation has to be as efficient as possible. - * - * @param classLoader a classloader. - * @return the result of the ignore evaluation. - */ - Result classloader(ClassLoader classLoader); - - /** Result of the ignore evaluation. */ - enum Result { - /** Default - delegate the evaluation to global ignore matchers from javaagent-tooling. */ - DEFAULT, - /** Ignore instrumentation for a type. */ - IGNORE, - /** Allow instrumentation for a type. */ - ALLOW - } -} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java index 8ea27543cd..e45b85aa44 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java @@ -18,18 +18,16 @@ import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.instrumentation.api.internal.BootstrapPackagePrefixesHolder; import io.opentelemetry.javaagent.spi.BootstrapPackagesProvider; -import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider; import io.opentelemetry.javaagent.tooling.config.ConfigInitializer; import io.opentelemetry.javaagent.tooling.context.FieldBackedProvider; +import io.opentelemetry.javaagent.tooling.ignore.IgnoredClassLoadersMatcher; import io.opentelemetry.javaagent.tooling.ignore.IgnoredTypesBuilderImpl; import io.opentelemetry.javaagent.tooling.ignore.IgnoredTypesMatcher; -import io.opentelemetry.javaagent.tooling.matcher.GlobalClassloaderIgnoresMatcher; import java.lang.instrument.Instrumentation; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ForkJoinPool; @@ -175,20 +173,14 @@ public class AgentInstaller { } private static AgentBuilder configureIgnoredTypes(Config config, AgentBuilder agentBuilder) { - IgnoreMatcherProvider ignoreMatcherProvider = loadIgnoreMatcherProvider(); - log.debug( - "Ignore matcher provider {} will be used", ignoreMatcherProvider.getClass().getName()); - - IgnoredTypesBuilderImpl ignoredTypesBuilder = new IgnoredTypesBuilderImpl(); + IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl(); for (IgnoredTypesConfigurer configurer : loadOrdered(IgnoredTypesConfigurer.class)) { - configurer.configure(config, ignoredTypesBuilder); + configurer.configure(config, builder); } return agentBuilder - .ignore(any(), GlobalClassloaderIgnoresMatcher.skipClassLoader(ignoreMatcherProvider)) - .or( - new IgnoredTypesMatcher( - ignoreMatcherProvider, ignoredTypesBuilder.buildIgnoredTypesTrie())); + .ignore(any(), new IgnoredClassLoadersMatcher(builder.buildIgnoredClassLoadersTrie())) + .or(new IgnoredTypesMatcher(builder.buildIgnoredTypesTrie())); } private static void runAfterAgentListeners( @@ -224,17 +216,6 @@ public class AgentInstaller { } } - private static IgnoreMatcherProvider loadIgnoreMatcherProvider() { - Iterable ignoreMatcherProviders = - SafeServiceLoader.load(IgnoreMatcherProvider.class); - - Iterator iterator = ignoreMatcherProviders.iterator(); - if (iterator.hasNext()) { - return iterator.next(); - } - return new NoopIgnoreMatcherProvider(); - } - private static void addByteBuddyRawSetting() { String savedPropertyValue = System.getProperty(TypeDefinition.RAW_TYPES_PROPERTY); try { @@ -500,19 +481,5 @@ public class AgentInstaller { "{} loaded on {}", AgentInstaller.class.getName(), AgentInstaller.class.getClassLoader()); } - /** This class will be removed together with {@link IgnoreMatcherProvider}. */ - @Deprecated - public static final class NoopIgnoreMatcherProvider implements IgnoreMatcherProvider { - @Override - public Result classloader(ClassLoader classLoader) { - return Result.DEFAULT; - } - - @Override - public Result type(TypeDescription target) { - return Result.DEFAULT; - } - } - private AgentInstaller() {} } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java index 932ef83d25..5724e2ef65 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java @@ -7,14 +7,22 @@ package io.opentelemetry.javaagent.tooling.ignore; import com.google.auto.service.AutoService; import io.opentelemetry.instrumentation.api.config.Config; +import io.opentelemetry.javaagent.bootstrap.AgentClassLoader; import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder; import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer; +import io.opentelemetry.javaagent.tooling.ExporterClassLoader; +import io.opentelemetry.javaagent.tooling.ExtensionClassLoader; @AutoService(IgnoredTypesConfigurer.class) public class GlobalIgnoredTypesConfigurer implements IgnoredTypesConfigurer { @Override public void configure(Config config, IgnoredTypesBuilder builder) { + configureIgnoredTypes(builder); + configureIgnoredClassLoaders(builder); + } + + private static void configureIgnoredTypes(IgnoredTypesBuilder builder) { builder .ignoreClass("org.gradle.") .ignoreClass("net.bytebuddy.") @@ -94,4 +102,25 @@ public class GlobalIgnoredTypesConfigurer implements IgnoredTypesConfigurer { // proxy, and as there is no reason why it should be instrumented anyway, exclude it. .ignoreClass("$HttpServletRequest_"); } + + private static void configureIgnoredClassLoaders(IgnoredTypesBuilder builder) { + builder + .ignoreClassLoader("org.codehaus.groovy.runtime.callsite.CallSiteClassLoader") + .ignoreClassLoader("sun.reflect.DelegatingClassLoader") + .ignoreClassLoader("jdk.internal.reflect.DelegatingClassLoader") + .ignoreClassLoader("clojure.lang.DynamicClassLoader") + .ignoreClassLoader("org.apache.cxf.common.util.ASMHelper$TypeHelperClassLoader") + .ignoreClassLoader("sun.misc.Launcher$ExtClassLoader") + .ignoreClassLoader(AgentClassLoader.class.getName()) + .ignoreClassLoader(ExporterClassLoader.class.getName()) + .ignoreClassLoader(ExtensionClassLoader.class.getName()); + + builder + .ignoreClassLoader("datadog.") + .ignoreClassLoader("com.dynatrace.") + .ignoreClassLoader("com.appdynamics.") + .ignoreClassLoader("com.newrelic.agent.") + .ignoreClassLoader("com.newrelic.api.agent.") + .ignoreClassLoader("com.nr.agent."); + } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/matcher/GlobalClassloaderIgnoresMatcher.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredClassLoadersMatcher.java similarity index 53% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/matcher/GlobalClassloaderIgnoresMatcher.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredClassLoadersMatcher.java index 32546bfb83..8309f552b0 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/matcher/GlobalClassloaderIgnoresMatcher.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredClassLoadersMatcher.java @@ -3,57 +3,45 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.tooling.matcher; +package io.opentelemetry.javaagent.tooling.ignore; import io.opentelemetry.instrumentation.api.caching.Cache; import io.opentelemetry.javaagent.bootstrap.PatchLogger; -import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider; +import io.opentelemetry.javaagent.tooling.ignore.trie.Trie; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.matcher.ElementMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class GlobalClassloaderIgnoresMatcher - extends ElementMatcher.Junction.AbstractBase { - private static final Logger log = LoggerFactory.getLogger(GlobalClassloaderIgnoresMatcher.class); +public class IgnoredClassLoadersMatcher extends ElementMatcher.Junction.AbstractBase { + private static final Logger log = LoggerFactory.getLogger(IgnoredClassLoadersMatcher.class); /* Cache of classloader-instance -> (true|false). True = skip instrumentation. False = safe to instrument. */ - private static final String AGENT_CLASSLOADER_NAME = - "io.opentelemetry.javaagent.bootstrap.AgentClassLoader"; - private static final String EXPORTER_CLASSLOADER_NAME = - "io.opentelemetry.javaagent.tooling.ExporterClassLoader"; private static final Cache skipCache = Cache.newBuilder().setWeakKeys().build(); - public static ElementMatcher.Junction.AbstractBase skipClassLoader( - IgnoreMatcherProvider ignoreMatcherProvider) { - return new GlobalClassloaderIgnoresMatcher(ignoreMatcherProvider); - } + private final Trie ignoredClassLoaders; - private final IgnoreMatcherProvider ignoreMatcherProviders; - - private GlobalClassloaderIgnoresMatcher(IgnoreMatcherProvider ignoreMatcherProviders) { - this.ignoreMatcherProviders = ignoreMatcherProviders; + public IgnoredClassLoadersMatcher(Trie ignoredClassLoaders) { + this.ignoredClassLoaders = ignoredClassLoaders; } @Override public boolean matches(ClassLoader cl) { - IgnoreMatcherProvider.Result ignoreResult = ignoreMatcherProviders.classloader(cl); - switch (ignoreResult) { - case IGNORE: - return true; - case ALLOW: - return false; - case DEFAULT: - } - if (cl == ClassLoadingStrategy.BOOTSTRAP_LOADER) { // Don't skip bootstrap loader return false; } - if (canSkipClassLoaderByName(cl)) { + + String name = cl.getClass().getName(); + + IgnoreAllow ignored = ignoredClassLoaders.getOrNull(name); + if (ignored == IgnoreAllow.ALLOW) { + return false; + } else if (ignored == IgnoreAllow.IGNORE) { return true; } + return skipCache.computeIfAbsent( cl, c -> { @@ -74,34 +62,6 @@ public class GlobalClassloaderIgnoresMatcher }); } - private static boolean canSkipClassLoaderByName(ClassLoader loader) { - String name = loader.getClass().getName(); - // check by FQCN - switch (name) { - case "org.codehaus.groovy.runtime.callsite.CallSiteClassLoader": - case "sun.reflect.DelegatingClassLoader": - case "jdk.internal.reflect.DelegatingClassLoader": - case "clojure.lang.DynamicClassLoader": - case "org.apache.cxf.common.util.ASMHelper$TypeHelperClassLoader": - case "sun.misc.Launcher$ExtClassLoader": - case AGENT_CLASSLOADER_NAME: - case EXPORTER_CLASSLOADER_NAME: - return true; - default: - // noop - } - // check by package prefix - if (name.startsWith("datadog.") - || name.startsWith("com.dynatrace.") - || name.startsWith("com.appdynamics.") - || name.startsWith("com.newrelic.agent.") - || name.startsWith("com.newrelic.api.agent.") - || name.startsWith("com.nr.agent.")) { - return true; - } - return false; - } - /** * TODO: this turns out to be useless with OSGi: {@code * org.eclipse.osgi.internal.loader.BundleLoader#isRequestFromVM} returns {@code true} when class diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java index 746a9fdeb2..6706f6268a 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java @@ -9,30 +9,31 @@ import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder; import io.opentelemetry.javaagent.tooling.ignore.trie.Trie; public class IgnoredTypesBuilderImpl implements IgnoredTypesBuilder { - private final Trie.Builder ignoreMatcherTrie = Trie.newBuilder(); + private final Trie.Builder ignoredTypesTrie = Trie.newBuilder(); + private final Trie.Builder ignoredClassLoadersTrie = Trie.newBuilder(); @Override - public IgnoredTypesBuilder ignoreClass(String className) { - ignoreMatcherTrie.put(className, IgnoreAllow.IGNORE); + public IgnoredTypesBuilder ignoreClass(String classNameOrPrefix) { + ignoredTypesTrie.put(classNameOrPrefix, IgnoreAllow.IGNORE); return this; } @Override - public IgnoredTypesBuilder allowClass(String className) { - ignoreMatcherTrie.put(className, IgnoreAllow.ALLOW); + public IgnoredTypesBuilder allowClass(String classNameOrPrefix) { + ignoredTypesTrie.put(classNameOrPrefix, IgnoreAllow.ALLOW); return this; } @Override public IgnoredTypesBuilder ignoreClassLoader(String classNameOrPrefix) { - // TODO: collect classloader classes into a separate trie - throw new UnsupportedOperationException("not implemented yet"); + ignoredClassLoadersTrie.put(classNameOrPrefix, IgnoreAllow.IGNORE); + return this; } @Override public IgnoredTypesBuilder allowClassLoader(String classNameOrPrefix) { - // TODO: collect classloader classes into a separate trie - throw new UnsupportedOperationException("not implemented yet"); + ignoredClassLoadersTrie.put(classNameOrPrefix, IgnoreAllow.ALLOW); + return this; } @Override @@ -48,6 +49,10 @@ public class IgnoredTypesBuilderImpl implements IgnoredTypesBuilder { } public Trie buildIgnoredTypesTrie() { - return ignoreMatcherTrie.build(); + return ignoredTypesTrie.build(); + } + + public Trie buildIgnoredClassLoadersTrie() { + return ignoredClassLoadersTrie.build(); } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java index e545653bbc..a10fd41525 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.tooling.ignore; -import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider; import io.opentelemetry.javaagent.tooling.ignore.trie.Trie; import java.util.regex.Pattern; import net.bytebuddy.description.type.TypeDescription; @@ -16,12 +15,9 @@ public class IgnoredTypesMatcher extends ElementMatcher.Junction.AbstractBase ignoredTypes; - public IgnoredTypesMatcher( - IgnoreMatcherProvider ignoreMatcherProvider, Trie ignoredTypes) { - this.ignoreMatcherProvider = ignoreMatcherProvider; + public IgnoredTypesMatcher(Trie ignoredTypes) { this.ignoredTypes = ignoredTypes; } @@ -29,14 +25,6 @@ public class IgnoredTypesMatcher extends ElementMatcher.Junction.AbstractBase IgnoreMatcherProvider.Result.DEFAULT }] as IgnoreMatcherProvider - - def "skips agent classloader"() { - setup: - URL url = AgentClassLoader.getProtectionDomain().getCodeSource().getLocation() - URLClassLoader agentLoader = new AgentClassLoader(new File(url.toURI()), "", null) - expect: - GlobalClassloaderIgnoresMatcher.skipClassLoader(matcherProvider).matches(agentLoader) - } - - def "skips exporter classloader"() { - setup: - URL url = new URL("file://") - URLClassLoader exporterLoader = new ExporterClassLoader(url, null) - expect: - GlobalClassloaderIgnoresMatcher.skipClassLoader(matcherProvider).matches(exporterLoader) - } - - def "does not skip empty classloader"() { - setup: - ClassLoader emptyLoader = new ClassLoader() {} - expect: - !GlobalClassloaderIgnoresMatcher.skipClassLoader(matcherProvider).matches(emptyLoader) - } - - def "does not skip bootstrap classloader"() { - expect: - !GlobalClassloaderIgnoresMatcher.skipClassLoader(matcherProvider).matches(null) - } - - def "skip bootstrap classloader"() { - IgnoreMatcherProvider skipBootstrapClMatcherProvider = [classloader: { cl -> cl == null ? IgnoreMatcherProvider.Result.IGNORE : IgnoreMatcherProvider.Result.DEFAULT }] as IgnoreMatcherProvider - expect: - GlobalClassloaderIgnoresMatcher.skipClassLoader(skipBootstrapClMatcherProvider).matches(null) - } - - def "AgentClassLoader class name is hardcoded in ClassLoaderMatcher"() { - expect: - AgentClassLoader.name == "io.opentelemetry.javaagent.bootstrap.AgentClassLoader" - } - - def "ExporterClassLoader class name is hardcoded in ClassLoaderMatcher"() { - expect: - ExporterClassLoader.name == "io.opentelemetry.javaagent.tooling.ExporterClassLoader" - } -}