Rewrite global ignores matcher to IgnoredTypesConfigurer
MODIFY
benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java
benchmark/src/jmh/java/io/opentelemetry/benchmark/IgnoredTypesMatcherBenchmark.java
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;
import java.util.concurrent.TimeUnit;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@@ -36,7 +38,9 @@ public class IgnoredTypesMatcherBenchmark {
static {
IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl();
new AdditionalLibraryIgnoredTypesConfigurer().configure(Config.get(), builder);
- ignoredTypesMatcher = builder.buildIgnoredTypesMatcher();
+ ignoredTypesMatcher =
+ new IgnoredTypesMatcher(
+ new AgentInstaller.NoopIgnoreMatcherProvider(), builder.buildIgnoredTypesTrie());
}
@Benchmark

MODIFY
javaagent-tooling/javaagent-tooling.gradle
javaagent-tooling/javaagent-tooling.gradle
@@ -45,6 +45,7 @@ dependencies {
testImplementation "com.google.guava:guava"
testImplementation "org.assertj:assertj-core"
testImplementation "org.mockito:mockito-core"
+ testImplementation "org.mockito:mockito-junit-jupiter"
instrumentationMuzzle sourceSets.main.output
}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java
@@ -8,10 +8,7 @@ package io.opentelemetry.javaagent.tooling;
import static io.opentelemetry.javaagent.bootstrap.AgentInitializer.isJavaBefore9;
import static io.opentelemetry.javaagent.tooling.SafeServiceLoader.loadOrdered;
import static io.opentelemetry.javaagent.tooling.Utils.getResourceName;
-import static io.opentelemetry.javaagent.tooling.matcher.GlobalIgnoresMatcher.globalIgnoresMatcher;
import static net.bytebuddy.matcher.ElementMatchers.any;
-import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
-import static net.bytebuddy.matcher.ElementMatchers.none;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.bootstrap.AgentClassLoader;
@@ -25,17 +22,16 @@ 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.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.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -44,9 +40,6 @@ import net.bytebuddy.agent.builder.ResettableClassFileTransformer;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
-import net.bytebuddy.matcher.ElementMatcher;
-import net.bytebuddy.matcher.NameMatcher;
-import net.bytebuddy.matcher.StringSetMatcher;
import net.bytebuddy.utility.JavaModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,7 +49,6 @@ public class AgentInstaller {
private static final Logger log;
private static final String JAVAAGENT_ENABLED_CONFIG = "otel.javaagent.enabled";
- private static final String EXCLUDED_CLASSES_CONFIG = "otel.javaagent.exclude-classes";
// This property may be set to force synchronous AgentListener#afterAgent() execution: the
// condition for delaying the AgentListener initialization is pretty broad and in case it covers
@@ -122,11 +114,7 @@ public class AgentInstaller {
FieldBackedProvider.resetContextMatchers();
- IgnoreMatcherProvider ignoreMatcherProvider = loadIgnoreMatcherProvider();
- log.debug(
- "Ignore matcher provider {} will be used", ignoreMatcherProvider.getClass().getName());
-
- AgentBuilder.Ignored ignoredAgentBuilder =
+ AgentBuilder agentBuilder =
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
@@ -134,19 +122,13 @@ public class AgentInstaller {
.with(AgentBuilder.DescriptionStrategy.Default.POOL_ONLY)
.with(AgentTooling.poolStrategy())
.with(new ClassLoadListener())
- .with(AgentTooling.locationStrategy())
+ .with(AgentTooling.locationStrategy());
// FIXME: we cannot enable it yet due to BB/JVM bug, see
// https://github.com/raphw/byte-buddy/issues/558
// .with(AgentBuilder.LambdaInstrumentationStrategy.ENABLED)
- .ignore(any(), GlobalClassloaderIgnoresMatcher.skipClassLoader(ignoreMatcherProvider));
- ignoredAgentBuilder =
- ignoredAgentBuilder.or(
- globalIgnoresMatcher(ignoreMatcherProvider, loadIgnoredTypesMatcher(config)));
+ agentBuilder = configureIgnoredTypes(config, agentBuilder);
- ignoredAgentBuilder = ignoredAgentBuilder.or(matchesConfiguredExcludes());
-
- AgentBuilder agentBuilder = ignoredAgentBuilder;
if (log.isDebugEnabled()) {
agentBuilder =
agentBuilder
@@ -180,14 +162,6 @@ public class AgentInstaller {
return resettableClassFileTransformer;
}
- private static ElementMatcher<TypeDescription> loadIgnoredTypesMatcher(Config config) {
- IgnoredTypesBuilderImpl ignoredTypesBuilder = new IgnoredTypesBuilderImpl();
- for (IgnoredTypesConfigurer configurer : loadOrdered(IgnoredTypesConfigurer.class)) {
- configurer.configure(config, ignoredTypesBuilder);
- }
- return ignoredTypesBuilder.buildIgnoredTypesMatcher();
- }
-
private static void runBeforeAgentListeners(
Iterable<AgentListener> agentListeners, Config config) {
for (AgentListener agentListener : agentListeners) {
@@ -195,6 +169,23 @@ 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();
+ for (IgnoredTypesConfigurer configurer : loadOrdered(IgnoredTypesConfigurer.class)) {
+ configurer.configure(config, ignoredTypesBuilder);
+ }
+
+ return agentBuilder
+ .ignore(any(), GlobalClassloaderIgnoresMatcher.skipClassLoader(ignoreMatcherProvider))
+ .or(
+ new IgnoredTypesMatcher(
+ ignoreMatcherProvider, ignoredTypesBuilder.buildIgnoredTypesTrie()));
+ }
+
private static void runAfterAgentListeners(
Iterable<AgentListener> agentListeners, Config config) {
// java.util.logging.LogManager maintains a final static LogManager, which is created during
@@ -256,33 +247,6 @@ public class AgentInstaller {
}
}
- // TODO: rewrite to an IgnoredTypesConfigurer
- private static ElementMatcher.Junction<? super TypeDescription> matchesConfiguredExcludes() {
- List<String> excludedClasses = Config.get().getListProperty(EXCLUDED_CLASSES_CONFIG);
- ElementMatcher.Junction<? super TypeDescription> matcher = none();
- Set<String> literals = new HashSet<>();
- List<String> prefixes = new ArrayList<>();
- // first accumulate by operation because a lot of work can be aggregated
- for (String excludedClass : excludedClasses) {
- excludedClass = excludedClass.trim();
- if (excludedClass.endsWith("*")) {
- // remove the trailing *
- prefixes.add(excludedClass.substring(0, excludedClass.length() - 1));
- } else {
- literals.add(excludedClass);
- }
- }
- if (!literals.isEmpty()) {
- matcher = matcher.or(new NameMatcher<>(new StringSetMatcher(literals)));
- }
- for (String prefix : prefixes) {
- // TODO - with a prefix tree this matching logic can be handled by a
- // single longest common prefix query
- matcher = matcher.or(nameStartsWith(prefix));
- }
- return matcher;
- }
-
private static List<String> loadBootstrapPackagePrefixes() {
List<String> bootstrapPackages = new ArrayList<>(Constants.BOOTSTRAP_PACKAGE_PREFIXES);
Iterable<BootstrapPackagesProvider> bootstrapPackagesProviders =
@@ -531,7 +495,9 @@ public class AgentInstaller {
"{} loaded on {}", AgentInstaller.class.getName(), AgentInstaller.class.getClassLoader());
}
- private static class NoopIgnoreMatcherProvider implements IgnoreMatcherProvider {
+ /** 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;

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/AdditionalLibraryIgnoredTypesConfigurer.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/AdditionalLibraryIgnoredTypesConfigurer.java
@@ -9,15 +9,14 @@ import com.google.auto.service.AutoService;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
-import io.opentelemetry.javaagent.tooling.matcher.GlobalIgnoresMatcher;
/**
* Additional global ignore settings that are used to reduce number of classes we try to apply
* expensive matchers to.
*
- * <p>This is separated from {@link GlobalIgnoresMatcher} to allow for better testing. The idea is
- * that we should be able to remove this matcher from the agent and all tests should still pass.
- * Moreover, no classes matched by this matcher should be modified during test run.
+ * <p>This is separated from {@link GlobalIgnoredTypesConfigurer} to allow for better testing. The
+ * idea is that we should be able to remove this matcher from the agent and all tests should still
+ * pass. Moreover, no classes matched by this matcher should be modified during test run.
*/
@AutoService(IgnoredTypesConfigurer.class)
public class AdditionalLibraryIgnoredTypesConfigurer implements IgnoredTypesConfigurer {

ADD
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.tooling.ignore;
+
+import com.google.auto.service.AutoService;
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
+
+@AutoService(IgnoredTypesConfigurer.class)
+public class GlobalIgnoredTypesConfigurer implements IgnoredTypesConfigurer {
+
+ @Override
+ public void configure(Config config, IgnoredTypesBuilder builder) {
+ builder
+ .ignoreClass("org.gradle.")
+ .ignoreClass("net.bytebuddy.")
+ .ignoreClass("jdk.")
+ .ignoreClass("org.aspectj.")
+ .ignoreClass("datadog.")
+ .ignoreClass("com.intellij.rt.debugger.")
+ .ignoreClass("com.p6spy.")
+ .ignoreClass("com.dynatrace.")
+ .ignoreClass("com.jloadtrace.")
+ .ignoreClass("com.appdynamics.")
+ .ignoreClass("com.newrelic.agent.")
+ .ignoreClass("com.newrelic.api.agent.")
+ .ignoreClass("com.nr.agent.")
+ .ignoreClass("com.singularity.")
+ .ignoreClass("com.jinspired.")
+ .ignoreClass("org.jinspired.");
+
+ // allow JDK HttpClient
+ builder.allowClass("jdk.internal.net.http.");
+
+ // groovy
+ builder
+ .ignoreClass("org.groovy.")
+ .ignoreClass("org.apache.groovy.")
+ .ignoreClass("org.codehaus.groovy.")
+ // We seem to instrument some classes in runtime
+ .allowClass("org.codehaus.groovy.runtime.");
+
+ // clojure
+ builder.ignoreClass("clojure.").ignoreClass("$fn__");
+
+ builder
+ .ignoreClass("io.opentelemetry.javaagent.")
+ // FIXME: We should remove this once
+ // https://github.com/raphw/byte-buddy/issues/558 is fixed
+ .allowClass("io.opentelemetry.javaagent.instrumentation.api.concurrent.RunnableWrapper")
+ .allowClass("io.opentelemetry.javaagent.instrumentation.api.concurrent.CallableWrapper");
+
+ builder
+ .ignoreClass("java.")
+ .allowClass("java.net.URL")
+ .allowClass("java.net.HttpURLConnection")
+ .allowClass("java.net.URLClassLoader")
+ .allowClass("java.rmi.")
+ .allowClass("java.util.concurrent.")
+ .allowClass("java.lang.reflect.Proxy")
+ .allowClass("java.lang.ClassLoader")
+ // Concurrent instrumentation modifies the structure of
+ // Cleaner class incompatibly with java9+ modules.
+ // Working around until a long-term fix for modules can be
+ // put in place.
+ .allowClass("java.util.logging.")
+ .ignoreClass("java.util.logging.LogManager$Cleaner");
+
+ builder
+ .ignoreClass("com.sun.")
+ .allowClass("com.sun.messaging.")
+ .allowClass("com.sun.jersey.api.client")
+ .allowClass("com.sun.appserv")
+ .allowClass("com.sun.faces")
+ .allowClass("com.sun.xml.ws");
+
+ builder
+ .ignoreClass("sun.")
+ .allowClass("sun.net.www.protocol.")
+ .allowClass("sun.rmi.server")
+ .allowClass("sun.rmi.transport")
+ .allowClass("sun.net.www.http.HttpClient");
+
+ builder.ignoreClass("org.slf4j.").allowClass("org.slf4j.MDC");
+
+ builder
+ .ignoreClass("org.springframework.core.$Proxy")
+ // Tapestry Proxy, check only specific class that we know would be instrumented since there
+ // is no common prefix for its proxies other than "$". ByteBuddy fails to instrument this
+ // proxy, and as there is no reason why it should be instrumented anyway, exclude it.
+ .ignoreClass("$HttpServletRequest_");
+ }
+}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoreAllow.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoreAllow.java
package io.opentelemetry.javaagent.tooling.ignore;
-enum IgnoreAllow {
+public enum IgnoreAllow {
IGNORE,
ALLOW
}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesBuilderImpl.java
@@ -7,8 +7,6 @@ package io.opentelemetry.javaagent.tooling.ignore;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
import io.opentelemetry.javaagent.tooling.ignore.trie.Trie;
-import net.bytebuddy.description.type.TypeDescription;
-import net.bytebuddy.matcher.ElementMatcher;
public class IgnoredTypesBuilderImpl implements IgnoredTypesBuilder {
private final Trie.Builder<IgnoreAllow> ignoreMatcherTrie = Trie.newBuilder();
@@ -49,7 +47,7 @@ public class IgnoredTypesBuilderImpl implements IgnoredTypesBuilder {
throw new UnsupportedOperationException("not implemented yet");
}
- public ElementMatcher<TypeDescription> buildIgnoredTypesMatcher() {
- return new IgnoredTypesMatcher(ignoreMatcherTrie.build());
+ public Trie<IgnoreAllow> buildIgnoredTypesTrie() {
+ return ignoreMatcherTrie.build();
}
}

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/IgnoredTypesMatcher.java
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;
import net.bytebuddy.matcher.ElementMatcher;
-class IgnoredTypesMatcher extends ElementMatcher.Junction.AbstractBase<TypeDescription> {
+public class IgnoredTypesMatcher extends ElementMatcher.Junction.AbstractBase<TypeDescription> {
+
+ private static final Pattern COM_MCHANGE_PROXY =
+ Pattern.compile("com\\.mchange\\.v2\\.c3p0\\..*Proxy");
+
+ private final IgnoreMatcherProvider ignoreMatcherProvider;
private final Trie<IgnoreAllow> ignoredTypes;
- IgnoredTypesMatcher(Trie<IgnoreAllow> ignoredTypes) {
+ public IgnoredTypesMatcher(
+ IgnoreMatcherProvider ignoreMatcherProvider, Trie<IgnoreAllow> ignoredTypes) {
+ this.ignoreMatcherProvider = ignoreMatcherProvider;
this.ignoredTypes = ignoredTypes;
}
@Override
public boolean matches(TypeDescription target) {
- IgnoreAllow ignored = ignoredTypes.getOrNull(target.getActualName());
- // ALLOW or null (default) mean that the type should not be ignored
- return ignored == IgnoreAllow.IGNORE;
+ String name = target.getActualName();
+
+ // TODO: will be removed together with IgnoreMatcherProvider
+ IgnoreMatcherProvider.Result ignoreResult = ignoreMatcherProvider.type(target);
+ if (ignoreResult == IgnoreMatcherProvider.Result.ALLOW) {
+ return false;
+ } else if (ignoreResult == IgnoreMatcherProvider.Result.IGNORE) {
+ return true;
+ }
+
+ IgnoreAllow ignored = ignoredTypes.getOrNull(name);
+ if (ignored == IgnoreAllow.ALLOW) {
+ return false;
+ } else if (ignored == IgnoreAllow.IGNORE) {
+ return true;
+ }
+
+ // bytecode proxies typically have $$ in their name
+ if (name.contains("$$")) {
+ // allow scala anonymous classes
+ return !name.contains("$$anon$");
+ }
+
+ if (name.contains("$JaxbAccessor")
+ || name.contains("CGLIB$$")
+ || name.contains("javassist")
+ || name.contains(".asm.")
+ || name.contains("$__sisu")
+ || name.contains("$$EnhancerByProxool$$")
+ // glassfish ejb proxy
+ // We skip instrumenting these because some instrumentations e.g. jax-rs instrument methods
+ // that are annotated with @Path in an interface implemented by the class. We don't really
+ // want to instrument these methods in generated classes as this would create spans that
+ // have the generated class name in them instead of the actual class that handles the call.
+ || name.contains("__EJB31_Generated__")) {
+ return true;
+ }
+
+ return COM_MCHANGE_PROXY.matcher(name).matches();
}
}

ADD
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/UserExcludedClassesConfigurer.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.tooling.ignore;
+
+import com.google.auto.service.AutoService;
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
+import java.util.List;
+
+@AutoService(IgnoredTypesConfigurer.class)
+public class UserExcludedClassesConfigurer implements IgnoredTypesConfigurer {
+
+ // visible for tests
+ static final String EXCLUDED_CLASSES_CONFIG = "otel.javaagent.exclude-classes";
+
+ @Override
+ public void configure(Config config, IgnoredTypesBuilder builder) {
+ List<String> excludedClasses = config.getListProperty(EXCLUDED_CLASSES_CONFIG);
+ for (String excludedClass : excludedClasses) {
+ excludedClass = excludedClass.trim();
+ // remove the trailing *
+ if (excludedClass.endsWith("*")) {
+ excludedClass = excludedClass.substring(0, excludedClass.length() - 1);
+ }
+ builder.ignoreClass(excludedClass);
+ }
+ }
+}

DELETE
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/matcher/GlobalIgnoresMatcher.java
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.tooling.matcher;
-
-import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider;
-import java.util.regex.Pattern;
-import net.bytebuddy.description.type.TypeDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-
-/**
- * Global ignores matcher used by the agent.
- *
- * <p>This matcher services two main purposes:
- * <li>
- *
- * <ul>
- * Ignore classes that are unsafe or pointless to transform. 'System' level classes like jvm
- * classes or groovy classes, other tracers, debuggers, etc.
- * </ul>
- */
-// TODO: rewrite to an IgnoredTypesConfigurer
-public class GlobalIgnoresMatcher extends ElementMatcher.Junction.AbstractBase<TypeDescription> {
-
- private static final Pattern COM_MCHANGE_PROXY =
- Pattern.compile("com\\.mchange\\.v2\\.c3p0\\..*Proxy");
-
- public static ElementMatcher.Junction<TypeDescription> globalIgnoresMatcher(
- IgnoreMatcherProvider ignoreMatcherProviders,
- ElementMatcher<TypeDescription> ignoredTypeMatcher) {
- return new GlobalIgnoresMatcher(ignoreMatcherProviders, ignoredTypeMatcher);
- }
-
- private final IgnoreMatcherProvider ignoreMatcherProvider;
- private final ElementMatcher<TypeDescription> ignoredTypeMatcher;
-
- private GlobalIgnoresMatcher(
- IgnoreMatcherProvider ignoreMatcherProvider,
- ElementMatcher<TypeDescription> ignoredTypeMatcher) {
- this.ignoreMatcherProvider = ignoreMatcherProvider;
- this.ignoredTypeMatcher = ignoredTypeMatcher;
- }
-
- /**
- * Be very careful about the types of matchers used in this section as they are called on every
- * class load, so they must be fast. Generally speaking try to only use name matchers as they
- * don't have to load additional info.
- */
- @Override
- public boolean matches(TypeDescription target) {
- IgnoreMatcherProvider.Result ignoreResult = ignoreMatcherProvider.type(target);
- switch (ignoreResult) {
- case IGNORE:
- return true;
- case ALLOW:
- return false;
- case DEFAULT:
- }
-
- String name = target.getActualName();
-
- if (name.startsWith("jdk.internal.net.http.")) {
- return false;
- }
-
- if (name.startsWith("org.gradle.")
- || name.startsWith("net.bytebuddy.")
- || name.startsWith("jdk.")
- || name.startsWith("org.aspectj.")
- || name.startsWith("datadog.")
- || name.startsWith("com.intellij.rt.debugger.")
- || name.startsWith("com.p6spy.")
- || name.startsWith("com.dynatrace.")
- || name.startsWith("com.jloadtrace.")
- || name.startsWith("com.appdynamics.")
- || name.startsWith("com.newrelic.agent.")
- || name.startsWith("com.newrelic.api.agent.")
- || name.startsWith("com.nr.agent.")
- || name.startsWith("com.singularity.")
- || name.startsWith("com.jinspired.")
- || name.startsWith("org.jinspired.")) {
- return true;
- }
-
- // groovy
- if (name.startsWith("org.groovy.") || name.startsWith("org.apache.groovy.")) {
- return true;
- }
- if (name.startsWith("org.codehaus.groovy.")) {
- // We seem to instrument some classes in runtime
- if (name.startsWith("org.codehaus.groovy.runtime.")) {
- return false;
- }
- return true;
- }
- // clojure
- if (name.startsWith("clojure.") || name.contains("$fn__")) {
- return true;
- }
-
- if (name.startsWith("io.opentelemetry.javaagent.")) {
- // FIXME: We should remove this once
- // https://github.com/raphw/byte-buddy/issues/558 is fixed
- if (name.equals("io.opentelemetry.javaagent.instrumentation.api.concurrent.RunnableWrapper")
- || name.equals(
- "io.opentelemetry.javaagent.instrumentation.api.concurrent.CallableWrapper")) {
- return false;
- }
- return true;
- }
-
- if (name.startsWith("java.")) {
- if (name.equals("java.net.URL")
- || name.equals("java.net.HttpURLConnection")
- || name.equals("java.net.URLClassLoader")) {
- return false;
- }
- if (name.startsWith("java.rmi.") || name.startsWith("java.util.concurrent.")) {
- return false;
- }
- if (name.equals("java.lang.reflect.Proxy")) {
- return false;
- }
- if (name.equals("java.lang.ClassLoader")) {
- return false;
- }
-
- // Concurrent instrumentation modifies the structure of
- // Cleaner class incompatibly with java9+ modules.
- // Working around until a long-term fix for modules can be
- // put in place.
- if (name.startsWith("java.util.logging.")
- && !name.equals("java.util.logging.LogManager$Cleaner")) {
- return false;
- }
-
- return true;
- }
-
- if (name.startsWith("com.sun.")) {
- if (name.startsWith("com.sun.messaging.")
- || name.startsWith("com.sun.jersey.api.client")
- || name.startsWith("com.sun.appserv")
- || name.startsWith("com.sun.faces")
- || name.startsWith("com.sun.xml.ws")) {
- return false;
- }
-
- return true;
- }
-
- if (name.startsWith("sun.")) {
- if (name.startsWith("sun.net.www.protocol.")
- || name.startsWith("sun.rmi.server")
- || name.startsWith("sun.rmi.transport")
- || name.equals("sun.net.www.http.HttpClient")) {
- return false;
- }
-
- return true;
- }
-
- if (name.startsWith("org.slf4j.")) {
- if (name.equals("org.slf4j.MDC")) {
- return false;
- }
-
- return true;
- }
-
- // bytecode proxies typically have $$ in their name
- if (name.contains("$$")) {
- // scala anonymous classes
- if (name.contains("$$anon$")) {
- return false;
- }
- return true;
- }
-
- if (name.contains("$JaxbAccessor")
- || name.contains("CGLIB$$")
- || name.contains("javassist")
- || name.contains(".asm.")
- || name.contains("$__sisu")
- || name.contains("$$EnhancerByProxool$$")
- // glassfish ejb proxy
- // We skip instrumenting these because some instrumentations e.g. jax-rs instrument methods
- // that are annotated with @Path in an interface implemented by the class. We don't really
- // want to instrument these methods in generated classes as this would create spans that
- // have the generated class name in them instead of the actual class that handles the call.
- || name.contains("__EJB31_Generated__")
- || name.startsWith("org.springframework.core.$Proxy")
- // Tapestry Proxy, check only specific class that we know would be instrumented since there
- // is no common prefix for its proxies other than "$". ByteBuddy fails to instrument this
- // proxy, and as there is no reason why it should be instrumented anyway, exclude it.
- || name.startsWith("$HttpServletRequest_")) {
- return true;
- }
-
- if (COM_MCHANGE_PROXY.matcher(name).matches()) {
- return true;
- }
-
- return ignoredTypeMatcher.matches(target);
- }
-
- @Override
- public String toString() {
- return "globalIgnoresMatcher()";
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof GlobalIgnoresMatcher;
- }
-
- @Override
- public int hashCode() {
- return 17;
- }
-}

ADD
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/ignore/UserExcludedClassesConfigurerTest.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.tooling.ignore;
+
+import static io.opentelemetry.javaagent.tooling.ignore.UserExcludedClassesConfigurer.EXCLUDED_CLASSES_CONFIG;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import io.opentelemetry.instrumentation.api.config.Config;
+import io.opentelemetry.instrumentation.api.config.ConfigBuilder;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
+import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class UserExcludedClassesConfigurerTest {
+ @Mock IgnoredTypesBuilder builder;
+
+ IgnoredTypesConfigurer underTest = new UserExcludedClassesConfigurer();
+
+ @Test
+ void shouldAddNothingToBuilderWhenPropertyIsEmpty() {
+ // when
+ underTest.configure(Config.create(emptyMap()), builder);
+
+ // then
+ verifyNoInteractions(builder);
+ }
+
+ @Test
+ void shouldIgnoreClassesAndPackages() {
+ // given
+ Config config =
+ new ConfigBuilder()
+ .readProperties(
+ singletonMap(
+ EXCLUDED_CLASSES_CONFIG,
+ "com.example.IgnoredClass,com.example.ignored.*,com.another_ignore"))
+ .build();
+
+ // when
+ underTest.configure(config, builder);
+
+ // then
+ verify(builder).ignoreClass("com.example.IgnoredClass");
+ verify(builder).ignoreClass("com.example.ignored.");
+ verify(builder).ignoreClass("com.another_ignore");
+ }
+}

RENAME
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/ignore/TrieTest.java
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/ignore/trie/TrieTest.java
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.tooling.ignore;
+package io.opentelemetry.javaagent.tooling.ignore.trie;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
-import io.opentelemetry.javaagent.tooling.ignore.trie.Trie;
import org.junit.jupiter.api.Test;
class TrieTest {

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
@@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.testing.bytebuddy;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.javaagent.tooling.ignore.AdditionalLibraryIgnoredTypesConfigurer;
+import io.opentelemetry.javaagent.tooling.ignore.IgnoreAllow;
import io.opentelemetry.javaagent.tooling.ignore.IgnoredTypesBuilderImpl;
+import io.opentelemetry.javaagent.tooling.ignore.trie.Trie;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -19,7 +21,6 @@ import java.util.function.Function;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
-import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.utility.JavaModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,17 +29,16 @@ public class TestAgentListener implements AgentBuilder.Listener {
private static final Logger logger = LoggerFactory.getLogger(TestAgentListener.class);
- private static final ElementMatcher<TypeDescription> GLOBAL_LIBRARIES_IGNORES_MATCHER;
+ private static final Trie<IgnoreAllow> ADDITIONAL_LIBRARIES_TRIE;
static {
IgnoredTypesBuilderImpl builder = new IgnoredTypesBuilderImpl();
new AdditionalLibraryIgnoredTypesConfigurer().configure(Config.get(), builder);
- GLOBAL_LIBRARIES_IGNORES_MATCHER = builder.buildIgnoredTypesMatcher();
+ ADDITIONAL_LIBRARIES_TRIE = builder.buildIgnoredTypesTrie();
}
public static void reset() {
INSTANCE.transformedClassesNames.clear();
- INSTANCE.transformedClassesTypes.clear();
INSTANCE.instrumentationErrorCount.set(0);
INSTANCE.skipTransformationConditions.clear();
INSTANCE.skipErrorConditions.clear();
@@ -50,9 +50,9 @@ public class TestAgentListener implements AgentBuilder.Listener {
public static List<String> getIgnoredButTransformedClassNames() {
List<String> names = new ArrayList<>();
- for (TypeDescription type : INSTANCE.transformedClassesTypes) {
- if (GLOBAL_LIBRARIES_IGNORES_MATCHER.matches(type)) {
- names.add(type.getActualName());
+ for (String name : INSTANCE.transformedClassesNames) {
+ if (ADDITIONAL_LIBRARIES_TRIE.getOrNull(name) == IgnoreAllow.IGNORE) {
+ names.add(name);
}
}
return names;
@@ -70,8 +70,6 @@ public class TestAgentListener implements AgentBuilder.Listener {
private final Set<String> transformedClassesNames =
Collections.newSetFromMap(new ConcurrentHashMap<>());
- private final Set<TypeDescription> transformedClassesTypes =
- Collections.newSetFromMap(new ConcurrentHashMap<>());
private final AtomicInteger instrumentationErrorCount = new AtomicInteger(0);
private final Set<Function<String, Boolean>> skipTransformationConditions =
Collections.newSetFromMap(new ConcurrentHashMap<>());
@@ -97,7 +95,6 @@ public class TestAgentListener implements AgentBuilder.Listener {
boolean loaded,
DynamicType dynamicType) {
transformedClassesNames.add(typeDescription.getActualName());
- transformedClassesTypes.add(typeDescription);
}
@Override

Rewrite global ignores matcher to IgnoredTypesConfigurer (#3298)