InstrumentationModule cleanup (#2925)

This commit is contained in:
Mateusz Rzeszutek 2021-05-11 18:24:31 +02:00 committed by GitHub
parent 3b807e0efb
commit 871f9a0d24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 159 deletions

View File

@ -55,7 +55,7 @@ public class MethodInstrumentationModule extends InstrumentationModule {
// the default configuration has empty "otel.instrumentation.methods.include", and so doesn't // the default configuration has empty "otel.instrumentation.methods.include", and so doesn't
// generate any TypeInstrumentation for muzzle to analyze // generate any TypeInstrumentation for muzzle to analyze
@Override @Override
protected String[] getMuzzleHelperClassNames() { public String[] getMuzzleHelperClassNames() {
return typeInstrumentations.isEmpty() return typeInstrumentations.isEmpty()
? new String[0] ? new String[0]
: new String[] {"io.opentelemetry.javaagent.instrumentation.methods.MethodTracer"}; : new String[] {"io.opentelemetry.javaagent.instrumentation.methods.MethodTracer"};

View File

@ -33,12 +33,12 @@ import net.bytebuddy.matcher.ElementMatcher;
*/ */
public abstract class InstrumentationModule implements AgentExtension { public abstract class InstrumentationModule implements AgentExtension {
private static final String[] EMPTY = new String[0]; private static final String[] EMPTY = new String[0];
private static final Reference[] EMPTY_REFS = new Reference[0];
private static final boolean DEFAULT_ENABLED = private static final boolean DEFAULT_ENABLED =
Config.get().getBooleanProperty("otel.instrumentation.common.default-enabled", true); Config.get().getBooleanProperty("otel.instrumentation.common.default-enabled", true);
private final Set<String> instrumentationNames; private final Set<String> instrumentationNames;
final boolean enabled;
/** /**
* Creates an instrumentation module. Note that all implementations of {@link * Creates an instrumentation module. Note that all implementations of {@link
@ -75,7 +75,6 @@ public abstract class InstrumentationModule implements AgentExtension {
throw new IllegalArgumentException("InstrumentationModules must be named"); throw new IllegalArgumentException("InstrumentationModules must be named");
} }
this.instrumentationNames = new LinkedHashSet<>(instrumentationNames); this.instrumentationNames = new LinkedHashSet<>(instrumentationNames);
this.enabled = Config.get().isInstrumentationEnabled(instrumentationNames, defaultEnabled());
} }
private static List<String> toList(String first, String[] rest) { private static List<String> toList(String first, String[] rest) {
@ -101,15 +100,17 @@ public abstract class InstrumentationModule implements AgentExtension {
return instrumentationNames.iterator().next(); return instrumentationNames.iterator().next();
} }
/** Returns true if this instrumentation module should be installed. */
public final boolean isEnabled() {
return Config.get().isInstrumentationEnabled(instrumentationNames, defaultEnabled());
}
/** /**
* Returns all helper classes that will be injected into the application classloader, both ones * Allows instrumentation modules to disable themselves by default, or to additionally disable
* provided by the implementation and ones that were collected by muzzle during compilation. * themselves on some other condition.
*/ */
public final List<String> getAllHelperClassNames() { protected boolean defaultEnabled() {
List<String> helperClassNames = new ArrayList<>(); return DEFAULT_ENABLED;
helperClassNames.addAll(asList(additionalHelperClassNames()));
helperClassNames.addAll(asList(getMuzzleHelperClassNames()));
return helperClassNames;
} }
/** /**
@ -127,83 +128,6 @@ public abstract class InstrumentationModule implements AgentExtension {
return false; return false;
} }
/**
* Returns a list of references to helper and library classes used in this module's type
* instrumentation advices.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/
public Reference[] getMuzzleReferences() {
return new Reference[0];
}
/**
* Returns a list of instrumentation helper classes, automatically detected by muzzle during
* compilation. Those helpers will be injected into the application classloader.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/
protected String[] getMuzzleHelperClassNames() {
return EMPTY;
}
/**
* Returns a map of {@code class-name to context-class-name}. Keys (and their subclasses) will be
* associated with a context class stored in the value.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/
protected Map<String, String> getMuzzleContextStoreClasses() {
return Collections.emptyMap();
}
/**
* Instrumentation modules can override this method to provide additional helper classes that are
* not located in instrumentation packages described in the {@code InstrumentationClassPredicate}
* class and {@link #isHelperClass(String)} (and not automatically detected by muzzle). These
* additional classes will be injected into the application classloader first.
*
* <p>Implementing {@link #isHelperClass(String)} is generally simpler and less error-prone
* compared to implementing this method.
*
* @deprecated Use {@link #isHelperClass(String)} instead.
*/
@Deprecated
protected String[] additionalHelperClassNames() {
return EMPTY;
}
/**
* Same as {@link #order()}.
*
* @deprecated use {@link #order()} instead.
*/
@Deprecated
public int getOrder() {
return 0;
}
/** {@inheritDoc} */
@Override
public int order() {
return getOrder();
}
/** Returns resource names to inject into the user's classloader. */ /** Returns resource names to inject into the user's classloader. */
public String[] helperResourceNames() { public String[] helperResourceNames() {
return EMPTY; return EMPTY;
@ -228,10 +152,47 @@ public abstract class InstrumentationModule implements AgentExtension {
public abstract List<TypeInstrumentation> typeInstrumentations(); public abstract List<TypeInstrumentation> typeInstrumentations();
/** /**
* Allows instrumentation modules to disable themselves by default, or to additionally disable * Returns a list of references to helper and library classes used in this module's type
* themselves on some other condition. * instrumentation advices.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/ */
protected boolean defaultEnabled() { public Reference[] getMuzzleReferences() {
return DEFAULT_ENABLED; return EMPTY_REFS;
}
/**
* Returns a list of instrumentation helper classes, automatically detected by muzzle during
* compilation. Those helpers will be injected into the application classloader.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/
public String[] getMuzzleHelperClassNames() {
return EMPTY;
}
/**
* Returns a map of {@code class-name to context-class-name}. Keys (and their subclasses) will be
* associated with a context class stored in the value.
*
* <p>The actual implementation of this method is generated automatically during compilation by
* the {@code io.opentelemetry.javaagent.tooling.muzzle.collector.MuzzleCodeGenerationPlugin}
* ByteBuddy plugin.
*
* <p><b>This method is generated automatically</b>: if you override it, the muzzle compile plugin
* will not generate a new implementation, it will leave the existing one.
*/
public Map<String, String> getMuzzleContextStoreClasses() {
return Collections.emptyMap();
} }
} }

View File

@ -16,7 +16,7 @@ import net.bytebuddy.matcher.ElementMatcher;
/** /**
* This class provides some custom ByteBuddy element matchers to use when applying instrumentation. * This class provides some custom ByteBuddy element matchers to use when applying instrumentation.
*/ */
public class AgentElementMatchers { public final class AgentElementMatchers {
public static ElementMatcher.Junction<TypeDescription> extendsClass( public static ElementMatcher.Junction<TypeDescription> extendsClass(
ElementMatcher<TypeDescription> matcher) { ElementMatcher<TypeDescription> matcher) {
@ -92,4 +92,6 @@ public class AgentElementMatchers {
} }
} }
} }
private AgentElementMatchers() {}
} }

View File

@ -74,4 +74,6 @@ public final class NameMatchers {
return (include && contained) || (!include && !contained); return (include && contained) || (!include && !contained);
} }
} }
private NameMatchers() {}
} }

View File

@ -1,34 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.spi;
import io.opentelemetry.javaagent.extension.spi.AgentExtension;
import java.lang.instrument.Instrumentation;
import net.bytebuddy.agent.builder.AgentBuilder;
/**
* {@link ByteBuddyAgentCustomizer} customizes ByteBuddy agent builder right before the agent is
* installed - {@link AgentBuilder#installOn(Instrumentation)}. This SPI can be used to customize
* {@link AgentBuilder} for vendor specific needs. For example install custom listeners or exclude
* classes. Use this SPI carefully because it can change {@link net.bytebuddy.ByteBuddy} behaviour.
*
* <p>This is a service provider interface that requires implementations to be registered in {@code
* META-INF/services} folder.
*
* @deprecated Use {@link AgentExtension} with correct {@link AgentExtension#order()} instead.
*/
@Deprecated
public interface ByteBuddyAgentCustomizer {
/**
* Customize ByteBuddy agent builder before {@link AgentBuilder#installOn(Instrumentation)} is
* called.
*
* @param agentBuilder ByteBuddy agent from {@code AgentInstaller}.
* @return customized agent builder.
*/
AgentBuilder customize(AgentBuilder agentBuilder);
}

View File

@ -49,11 +49,11 @@ public final class ActualInstrumentationExtensionImplementation
@Override @Override
AgentBuilder extend( AgentBuilder extend(
InstrumentationModule instrumentationModule, AgentBuilder parentAgentBuilder) { InstrumentationModule instrumentationModule, AgentBuilder parentAgentBuilder) {
if (!instrumentationModule.enabled) { if (!instrumentationModule.isEnabled()) {
log.debug("Instrumentation {} is disabled", instrumentationModule.extensionName()); log.debug("Instrumentation {} is disabled", instrumentationModule.extensionName());
return parentAgentBuilder; return parentAgentBuilder;
} }
List<String> helperClassNames = instrumentationModule.getAllHelperClassNames(); List<String> helperClassNames = asList(instrumentationModule.getMuzzleHelperClassNames());
List<String> helperResourceNames = asList(instrumentationModule.helperResourceNames()); List<String> helperResourceNames = asList(instrumentationModule.helperResourceNames());
List<TypeInstrumentation> typeInstrumentations = instrumentationModule.typeInstrumentations(); List<TypeInstrumentation> typeInstrumentations = instrumentationModule.typeInstrumentations();
if (typeInstrumentations.isEmpty()) { if (typeInstrumentations.isEmpty()) {
@ -68,7 +68,7 @@ public final class ActualInstrumentationExtensionImplementation
ElementMatcher.Junction<ClassLoader> moduleClassLoaderMatcher = ElementMatcher.Junction<ClassLoader> moduleClassLoaderMatcher =
instrumentationModule.classLoaderMatcher(); instrumentationModule.classLoaderMatcher();
MuzzleMatcher muzzleMatcher = new MuzzleMatcher(instrumentationModule); MuzzleMatcher muzzleMatcher = new MuzzleMatcher(instrumentationModule, helperClassNames);
AgentBuilder.Transformer helperInjector = AgentBuilder.Transformer helperInjector =
new HelperInjector( new HelperInjector(
instrumentationModule.extensionName(), helperClassNames, helperResourceNames); instrumentationModule.extensionName(), helperClassNames, helperResourceNames);
@ -135,11 +135,14 @@ public final class ActualInstrumentationExtensionImplementation
*/ */
private static class MuzzleMatcher implements AgentBuilder.RawMatcher { private static class MuzzleMatcher implements AgentBuilder.RawMatcher {
private final InstrumentationModule instrumentationModule; private final InstrumentationModule instrumentationModule;
private final List<String> helperClassNames;
private final AtomicBoolean initialized = new AtomicBoolean(false); private final AtomicBoolean initialized = new AtomicBoolean(false);
private volatile ReferenceMatcher referenceMatcher; private volatile ReferenceMatcher referenceMatcher;
private MuzzleMatcher(InstrumentationModule instrumentationModule) { private MuzzleMatcher(
InstrumentationModule instrumentationModule, List<String> helperClassNames) {
this.instrumentationModule = instrumentationModule; this.instrumentationModule = instrumentationModule;
this.helperClassNames = helperClassNames;
} }
@Override @Override
@ -185,7 +188,7 @@ public final class ActualInstrumentationExtensionImplementation
if (initialized.compareAndSet(false, true)) { if (initialized.compareAndSet(false, true)) {
referenceMatcher = referenceMatcher =
new ReferenceMatcher( new ReferenceMatcher(
instrumentationModule.getAllHelperClassNames(), helperClassNames,
instrumentationModule.getMuzzleReferences(), instrumentationModule.getMuzzleReferences(),
instrumentationModule::isHelperClass); instrumentationModule::isHelperClass);
} }

View File

@ -20,7 +20,6 @@ import io.opentelemetry.javaagent.extension.spi.AgentExtension;
import io.opentelemetry.javaagent.instrumentation.api.SafeServiceLoader; import io.opentelemetry.javaagent.instrumentation.api.SafeServiceLoader;
import io.opentelemetry.javaagent.instrumentation.api.internal.BootstrapPackagePrefixesHolder; import io.opentelemetry.javaagent.instrumentation.api.internal.BootstrapPackagePrefixesHolder;
import io.opentelemetry.javaagent.spi.BootstrapPackagesProvider; import io.opentelemetry.javaagent.spi.BootstrapPackagesProvider;
import io.opentelemetry.javaagent.spi.ByteBuddyAgentCustomizer;
import io.opentelemetry.javaagent.spi.ComponentInstaller; import io.opentelemetry.javaagent.spi.ComponentInstaller;
import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider; import io.opentelemetry.javaagent.spi.IgnoreMatcherProvider;
import io.opentelemetry.javaagent.tooling.config.ConfigInitializer; import io.opentelemetry.javaagent.tooling.config.ConfigInitializer;
@ -170,7 +169,6 @@ public class AgentInstaller {
} }
} }
agentBuilder = customizeByteBuddyAgent(agentBuilder);
log.debug("Installed {} instrumenter(s)", numInstrumenters); log.debug("Installed {} instrumenter(s)", numInstrumenters);
ResettableClassFileTransformer resettableClassFileTransformer = agentBuilder.installOn(inst); ResettableClassFileTransformer resettableClassFileTransformer = agentBuilder.installOn(inst);
installComponentsAfterByteBuddy(componentInstallers, config); installComponentsAfterByteBuddy(componentInstallers, config);
@ -221,15 +219,6 @@ public class AgentInstaller {
} }
} }
private static AgentBuilder customizeByteBuddyAgent(AgentBuilder agentBuilder) {
Iterable<ByteBuddyAgentCustomizer> agentCustomizers = loadByteBuddyAgentCustomizers();
for (ByteBuddyAgentCustomizer agentCustomizer : agentCustomizers) {
log.debug("Applying agent builder customizer {}", agentCustomizer.getClass().getName());
agentBuilder = agentCustomizer.customize(agentBuilder);
}
return agentBuilder;
}
private static Iterable<ComponentInstaller> loadComponentProviders() { private static Iterable<ComponentInstaller> loadComponentProviders() {
return ServiceLoader.load(ComponentInstaller.class, AgentInstaller.class.getClassLoader()); return ServiceLoader.load(ComponentInstaller.class, AgentInstaller.class.getClassLoader());
} }
@ -245,11 +234,6 @@ public class AgentInstaller {
return new NoopIgnoreMatcherProvider(); return new NoopIgnoreMatcherProvider();
} }
private static Iterable<ByteBuddyAgentCustomizer> loadByteBuddyAgentCustomizers() {
return ServiceLoader.load(
ByteBuddyAgentCustomizer.class, AgentInstaller.class.getClassLoader());
}
private static List<? extends AgentExtension> loadAgentExtensions() { private static List<? extends AgentExtension> loadAgentExtensions() {
// TODO: InstrumentationModule should no longer be an SPI // TODO: InstrumentationModule should no longer be an SPI
Stream<? extends AgentExtension> extensions = Stream<? extends AgentExtension> extensions =

View File

@ -195,7 +195,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
private void generateMuzzleHelperClassNamesMethod(ReferenceCollector collector) { private void generateMuzzleHelperClassNamesMethod(ReferenceCollector collector) {
/* /*
* protected String[] getMuzzleHelperClassNames() { * public String[] getMuzzleHelperClassNames() {
* return new String[] { * return new String[] {
* // sorted helper class names * // sorted helper class names
* }; * };
@ -203,7 +203,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
*/ */
MethodVisitor mv = MethodVisitor mv =
super.visitMethod( super.visitMethod(
Opcodes.ACC_PROTECTED, Opcodes.ACC_PUBLIC,
MUZZLE_HELPER_CLASSES_METHOD_NAME, MUZZLE_HELPER_CLASSES_METHOD_NAME,
"()[Ljava/lang/String;", "()[Ljava/lang/String;",
null, null,
@ -236,7 +236,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
private void generateMuzzleReferencesMethod(ReferenceCollector collector) { private void generateMuzzleReferencesMethod(ReferenceCollector collector) {
/* /*
* protected synchronized Reference[] getMuzzleReferences() { * public synchronized Reference[] getMuzzleReferences() {
* if (null == this.muzzleReferences) { * if (null == this.muzzleReferences) {
* this.muzzleReferences = new Reference[] { * this.muzzleReferences = new Reference[] {
* // reference builders * // reference builders
@ -248,7 +248,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
try { try {
MethodVisitor mv = MethodVisitor mv =
super.visitMethod( super.visitMethod(
Opcodes.ACC_PROTECTED + Opcodes.ACC_SYNCHRONIZED, Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNCHRONIZED,
MUZZLE_REFERENCES_METHOD_NAME, MUZZLE_REFERENCES_METHOD_NAME,
"()[Lio/opentelemetry/javaagent/extension/muzzle/Reference;", "()[Lio/opentelemetry/javaagent/extension/muzzle/Reference;",
null, null,
@ -534,7 +534,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
private void generateMuzzleContextStoreClassesMethod(ReferenceCollector collector) { private void generateMuzzleContextStoreClassesMethod(ReferenceCollector collector) {
/* /*
* protected Map<String, String> getMuzzleContextStoreClasses() { * public Map<String, String> getMuzzleContextStoreClasses() {
* Map<String, String> contextStore = new HashMap(); * Map<String, String> contextStore = new HashMap();
* contextStore.put(..., ...); * contextStore.put(..., ...);
* return contextStore; * return contextStore;
@ -542,7 +542,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
*/ */
MethodVisitor mv = MethodVisitor mv =
super.visitMethod( super.visitMethod(
Opcodes.ACC_PROTECTED, Opcodes.ACC_PUBLIC,
MUZZLE_CONTEXT_STORE_CLASSES_METHOD_NAME, MUZZLE_CONTEXT_STORE_CLASSES_METHOD_NAME,
"()Ljava/util/Map;", "()Ljava/util/Map;",
null, null,

View File

@ -5,6 +5,8 @@
package io.opentelemetry.javaagent.tooling.muzzle.matcher; package io.opentelemetry.javaagent.tooling.muzzle.matcher;
import static java.util.Arrays.asList;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.muzzle.Reference; import io.opentelemetry.javaagent.extension.muzzle.Reference;
import io.opentelemetry.javaagent.tooling.HelperInjector; import io.opentelemetry.javaagent.tooling.HelperInjector;
@ -49,7 +51,7 @@ public final class MuzzleGradlePluginUtil {
ServiceLoader.load(InstrumentationModule.class, agentClassLoader)) { ServiceLoader.load(InstrumentationModule.class, agentClassLoader)) {
ReferenceMatcher muzzle = ReferenceMatcher muzzle =
new ReferenceMatcher( new ReferenceMatcher(
instrumentationModule.getAllHelperClassNames(), asList(instrumentationModule.getMuzzleHelperClassNames()),
instrumentationModule.getMuzzleReferences(), instrumentationModule.getMuzzleReferences(),
instrumentationModule::isHelperClass); instrumentationModule::isHelperClass);
List<Mismatch> mismatches = muzzle.getMismatchedReferenceSources(userClassLoader); List<Mismatch> mismatches = muzzle.getMismatchedReferenceSources(userClassLoader);
@ -88,7 +90,7 @@ public final class MuzzleGradlePluginUtil {
ServiceLoader.load(InstrumentationModule.class, agentClassLoader)) { ServiceLoader.load(InstrumentationModule.class, agentClassLoader)) {
try { try {
// verify helper injector works // verify helper injector works
List<String> allHelperClasses = instrumentationModule.getAllHelperClassNames(); List<String> allHelperClasses = asList(instrumentationModule.getMuzzleHelperClassNames());
if (!allHelperClasses.isEmpty()) { if (!allHelperClasses.isEmpty()) {
new HelperInjector( new HelperInjector(
MuzzleGradlePluginUtil.class.getSimpleName(), MuzzleGradlePluginUtil.class.getSimpleName(),

View File

@ -6,13 +6,19 @@
package io.opentelemetry.javaagent.testing.bytebuddy; package io.opentelemetry.javaagent.testing.bytebuddy;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.spi.ByteBuddyAgentCustomizer; import io.opentelemetry.javaagent.extension.spi.AgentExtension;
import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.agent.builder.AgentBuilder;
@AutoService(ByteBuddyAgentCustomizer.class) @AutoService(AgentExtension.class)
public class TestByteBuddyAgentCustomizer implements ByteBuddyAgentCustomizer { public class TestAgentExtension implements AgentExtension {
@Override @Override
public AgentBuilder customize(AgentBuilder agentBuilder) { public AgentBuilder extend(AgentBuilder agentBuilder) {
return agentBuilder.with(TestAgentListener.INSTANCE); return agentBuilder.with(TestAgentListener.INSTANCE);
} }
@Override
public String extensionName() {
return "test";
}
} }