diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java index 7010d067cb..6003586367 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java @@ -1,23 +1,50 @@ package datadog.trace.agent.tooling; import static datadog.trace.agent.tooling.Utils.getConfigEnabled; +import static net.bytebuddy.matcher.ElementMatchers.any; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +/** + * Built-in bytebuddy-based instrumentation for the datadog javaagent. + * + *

It is strongly recommended to extend {@link Default} rather than implement this interface + * directly. + */ public interface Instrumenter { + /** + * Add this instrumentation to an AgentBuilder. + * + * @param agentBuilder AgentBuilder to base instrumentation config off of. + * @return the original agentBuilder and this instrumentation + */ AgentBuilder instrument(AgentBuilder agentBuilder); + /** @return A type matcher used to match the class under transform. */ + ElementMatcher typeMatcher(); + + /** @return A type matcher used to match the classloader under transform */ + ElementMatcher classLoaderMatcher(); + + /** @return Class names of helpers to inject into the user's classloader */ + String[] helperClassNames(); + + Map transformers(); + @Slf4j - abstract class Configurable implements Instrumenter { + abstract class Default implements Instrumenter { private final Set instrumentationNames; protected final boolean enabled; - public Configurable(final String instrumentationName, final String... additionalNames) { + public Default(final String instrumentationName, final String... additionalNames) { this.instrumentationNames = new HashSet<>(Arrays.asList(additionalNames)); instrumentationNames.add(instrumentationName); @@ -37,21 +64,46 @@ public interface Instrumenter { enabled = anyEnabled; } - protected boolean defaultEnabled() { - return getConfigEnabled("dd.integrations.enabled", true); - } - @Override - public final AgentBuilder instrument(final AgentBuilder agentBuilder) { - if (enabled) { - return apply(agentBuilder); - } else { + public AgentBuilder instrument(final AgentBuilder agentBuilder) { + if (!enabled) { log.debug("Instrumentation {} is disabled", this); return agentBuilder; } + + AgentBuilder.Identified.Extendable advice = + agentBuilder + .type(typeMatcher(), classLoaderMatcher()) + .transform(DDTransformers.defaultTransformers()); + final String[] helperClassNames = helperClassNames(); + if (helperClassNames.length > 0) { + advice = advice.transform(new HelperInjector(helperClassNames)); + } + for (Map.Entry entry : transformers().entrySet()) { + advice = advice.transform(DDAdvice.create().advice(entry.getKey(), entry.getValue())); + } + return advice.asDecorator(); } - protected abstract AgentBuilder apply(AgentBuilder agentBuilder); + @Override + public String[] helperClassNames() { + return new String[0]; + } + + @Override + public ElementMatcher classLoaderMatcher() { + return any(); + } + + @Override + public abstract ElementMatcher typeMatcher(); + + @Override + public abstract Map transformers(); + + protected boolean defaultEnabled() { + return getConfigEnabled("dd.integrations.enabled", true); + } protected static String getPropOrEnv(final String name) { return System.getProperty(name, System.getenv(propToEnvName(name))); diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/NewInstrumenter.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/NewInstrumenter.java deleted file mode 100644 index c1c1f9048c..0000000000 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/NewInstrumenter.java +++ /dev/null @@ -1,130 +0,0 @@ -package datadog.trace.agent.tooling; - -import static datadog.trace.agent.tooling.Utils.getConfigEnabled; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.agent.builder.AgentBuilder.Matchable; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; - -/** - * Built-in bytebuddy-based instrumentation for the datadog javaagent. - * - * It is strongly recommended to extend {@link Configurable} rather than implement this interface directly. - */ -public interface NewInstrumenter { - - /** - * Add this instrumentation to an AgentBuilder. - * - * @param agentBuilder AgentBuilder to base instrumentation config off of. - * @return the original agentBuilder and this instrumentation - */ - AgentBuilder instrument(AgentBuilder agentBuilder); - - // the following methods would be implemented by the instrumentation author - - /** - * @return A type matcher used to match the class under transform. - */ - ElementMatcher getTypeMatcher(); - - /** - * @return A type matcher used to match the classloader under transform - */ - ElementMatcher getClassLoaderMatcher(); - - /** - * - * @return - */ - Set getHelperClassNames(); - - Map getTransformers(); - - // TODO: rename Configurable -> Default - @Slf4j - abstract class Configurable implements NewInstrumenter { - // omitted: config and name logic - - @Override - public final AgentBuilder instrument(final AgentBuilder agentBuilder) { - if (!enabled) { - log.debug("Instrumentation {} is disabled", this); - return agentBuilder; - } - - /* - Transformer transformer = AgentBuilder.type(createTypeMatcher(), ) - .and(safeToInject()) // implementation generated by muzzle - .transform(DDTransformers.defaultTransformers()) - .transform(new HelperInjector(getHelperClassNames())); - Map advice = getTransformers(); - for (Entry entry : advice.getEntrySet()) { - transformer = transformer.transform(DDAdvice.create().advice(entry.getKey(), entry.getValue())); - } - return transformer.asDecorator() - */ - // FIXME - return null; - } - - @Override - public Set getHelperClassNames() { - // FIXME - return null; - } - - public abstract ElementMatcher getTypeMatcher(); - - public abstract ElementMatcher getClassLoaderMatcher(); - - public abstract Map getTransformers(); - - - // TODO merge in config logic from previous instrumenter - - private final Set instrumentationNames; - protected final boolean enabled; - - public Configurable(final String instrumentationName, final String... additionalNames) { - this.instrumentationNames = new HashSet<>(Arrays.asList(additionalNames)); - instrumentationNames.add(instrumentationName); - - // If default is enabled, we want to enable individually, - // if default is disabled, we want to disable individually. - final boolean defaultEnabled = defaultEnabled(); - boolean anyEnabled = defaultEnabled; - for (final String name : instrumentationNames) { - final boolean configEnabled = - getConfigEnabled("dd.integration." + name + ".enabled", defaultEnabled); - if (defaultEnabled) { - anyEnabled &= configEnabled; - } else { - anyEnabled |= configEnabled; - } - } - enabled = anyEnabled; - } - - protected boolean defaultEnabled() { - return getConfigEnabled("dd.integrations.enabled", true); - } - - protected abstract AgentBuilder apply(AgentBuilder agentBuilder); - - protected static String getPropOrEnv(final String name) { - return System.getProperty(name, System.getenv(propToEnvName(name))); - } - - private static String propToEnvName(final String name) { - return name.toUpperCase().replace(".", "_"); - } - } -} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ConfigurableInstrumenterTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/DefaultInstrumenterTest.groovy similarity index 74% rename from dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ConfigurableInstrumenterTest.groovy rename to dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/DefaultInstrumenterTest.groovy index bce1ac83e6..962f6ec2b1 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ConfigurableInstrumenterTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/DefaultInstrumenterTest.groovy @@ -2,12 +2,14 @@ package datadog.trace.agent.test import datadog.trace.agent.tooling.Instrumenter import net.bytebuddy.agent.builder.AgentBuilder +import net.bytebuddy.description.type.TypeDescription +import net.bytebuddy.matcher.ElementMatcher import org.junit.Rule import org.junit.contrib.java.lang.system.EnvironmentVariables import org.junit.contrib.java.lang.system.RestoreSystemProperties import spock.lang.Specification -class ConfigurableInstrumenterTest extends Specification { +class DefaultInstrumenterTest extends Specification { @Rule public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties() @Rule @@ -20,8 +22,8 @@ class ConfigurableInstrumenterTest extends Specification { def "default enabled"() { setup: - def target = new TestConfigurableInstrumenter("test") - target.instrument(null) + def target = new TestDefaultInstrumenter("test") + target.instrument(new AgentBuilder.Default()) expect: target.enabled @@ -29,20 +31,22 @@ class ConfigurableInstrumenterTest extends Specification { } def "default enabled override"() { + setup: + target.instrument(new AgentBuilder.Default()) + expect: - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled where: enabled | target - true | new TestConfigurableInstrumenter("test") { + true | new TestDefaultInstrumenter("test") { @Override protected boolean defaultEnabled() { return true } } - false | new TestConfigurableInstrumenter("test") { + false | new TestDefaultInstrumenter("test") { @Override protected boolean defaultEnabled() { return false @@ -53,15 +57,15 @@ class ConfigurableInstrumenterTest extends Specification { def "default disabled can override to enabled"() { setup: System.setProperty("dd.integration.test.enabled", "$enabled") - def target = new TestConfigurableInstrumenter("test") { + def target = new TestDefaultInstrumenter("test") { @Override protected boolean defaultEnabled() { return false } } + target.instrument(new AgentBuilder.Default()) expect: - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled @@ -72,10 +76,10 @@ class ConfigurableInstrumenterTest extends Specification { def "configure default sys prop as #value"() { setup: System.setProperty("dd.integrations.enabled", value) - def target = new TestConfigurableInstrumenter("test") + def target = new TestDefaultInstrumenter("test") + target.instrument(new AgentBuilder.Default()) expect: - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled @@ -89,10 +93,10 @@ class ConfigurableInstrumenterTest extends Specification { def "configure default env var as #value"() { setup: environmentVariables.set("DD_INTEGRATIONS_ENABLED", value) - def target = new TestConfigurableInstrumenter("test") + def target = new TestDefaultInstrumenter("test") + target.instrument(new AgentBuilder.Default()) expect: - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled @@ -107,10 +111,10 @@ class ConfigurableInstrumenterTest extends Specification { setup: System.setProperty("dd.integrations.enabled", "false") System.setProperty("dd.integration.${value}.enabled", "true") - def target = new TestConfigurableInstrumenter(name, altName) + def target = new TestDefaultInstrumenter(name, altName) + target.instrument(new AgentBuilder.Default()) expect: - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled @@ -129,11 +133,11 @@ class ConfigurableInstrumenterTest extends Specification { setup: environmentVariables.set("DD_INTEGRATIONS_ENABLED", "false") environmentVariables.set("DD_INTEGRATION_${value}_ENABLED", "true") - def target = new TestConfigurableInstrumenter(name, altName) + def target = new TestDefaultInstrumenter(name, altName) + target.instrument(new AgentBuilder.Default()) expect: System.getenv("DD_INTEGRATION_${value}_ENABLED") == "true" - target.instrument(null) == null target.enabled == enabled target.applyCalled == enabled @@ -148,27 +152,37 @@ class ConfigurableInstrumenterTest extends Specification { "PERIOD_TEST" | true | "period.test" | "asdf" } - class TestConfigurableInstrumenter extends Instrumenter.Configurable { + class TestDefaultInstrumenter extends Instrumenter.Default { boolean applyCalled = false - TestConfigurableInstrumenter( + TestDefaultInstrumenter( String instrumentationName) { super(instrumentationName) } - TestConfigurableInstrumenter( + TestDefaultInstrumenter( String instrumentationName, String additionalName) { super(instrumentationName, [additionalName]) } - @Override - protected AgentBuilder apply(AgentBuilder agentBuilder) { - applyCalled = true - return null - } - def getEnabled() { return super.enabled } + + @Override + ElementMatcher typeMatcher() { + applyCalled = true + return new ElementMatcher() { + @Override + boolean matches(Object target) { + return false + } + } + } + + @Override + Map transformers() { + return Collections.emptyMap() + } } } diff --git a/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerInstrumentation.java b/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerInstrumentation.java index e9a7e655c9..4509644f5d 100644 --- a/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerInstrumentation.java +++ b/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerInstrumentation.java @@ -18,13 +18,11 @@ import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMap; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.util.*; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; import scala.Function1; import scala.concurrent.ExecutionContext; import scala.concurrent.Future; @@ -32,7 +30,7 @@ import scala.runtime.AbstractFunction1; @Slf4j @AutoService(Instrumenter.class) -public final class AkkaHttpServerInstrumentation extends Instrumenter.Configurable { +public final class AkkaHttpServerInstrumentation extends Instrumenter.Default { public AkkaHttpServerInstrumentation() { super("akka-http", "akka-http-server"); } @@ -42,38 +40,39 @@ public final class AkkaHttpServerInstrumentation extends Instrumenter.Configurab return false; } - private static final HelperInjector akkaHttpHelperInjector = - new HelperInjector( - AkkaHttpServerInstrumentation.class.getName() + "$DatadogWrapperHelper", - AkkaHttpServerInstrumentation.class.getName() + "$DatadogSyncWrapper", - AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper", - AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$1", - AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$2", - AkkaHttpServerInstrumentation.class.getName() + "$AkkaHttpServerHeaders"); + @Override + public ElementMatcher typeMatcher() { + return named("akka.http.scaladsl.HttpExt"); + } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(named("akka.http.scaladsl.HttpExt")) - .transform(DDTransformers.defaultTransformers()) - .transform(akkaHttpHelperInjector) - // Instrumenting akka-streams bindAndHandle api was previously attempted. - // This proved difficult as there was no clean way to close the async scope - // in the graph logic after the user's request handler completes. - // - // Instead, we're instrumenting the bindAndHandle function helpers by - // wrapping the scala functions with our own handlers. - .transform( - DDAdvice.create() - .advice( - named("bindAndHandleSync").and(takesArgument(0, named("scala.Function1"))), - AkkaHttpSyncAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - named("bindAndHandleAsync").and(takesArgument(0, named("scala.Function1"))), - AkkaHttpAsyncAdvice.class.getName())) - .asDecorator(); + public String[] helperClassNames() { + return new String[] { + AkkaHttpServerInstrumentation.class.getName() + "$DatadogWrapperHelper", + AkkaHttpServerInstrumentation.class.getName() + "$DatadogSyncWrapper", + AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper", + AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$1", + AkkaHttpServerInstrumentation.class.getName() + "$DatadogAsyncWrapper$2", + AkkaHttpServerInstrumentation.class.getName() + "$AkkaHttpServerHeaders" + }; + } + + @Override + public Map transformers() { + // Instrumenting akka-streams bindAndHandle api was previously attempted. + // This proved difficult as there was no clean way to close the async scope + // in the graph logic after the user's request handler completes. + // + // Instead, we're instrumenting the bindAndHandle function helpers by + // wrapping the scala functions with our own handlers. + final Map transformers = new HashMap<>(); + transformers.put( + named("bindAndHandleSync").and(takesArgument(0, named("scala.Function1"))), + AkkaHttpSyncAdvice.class.getName()); + transformers.put( + named("bindAndHandleAsync").and(takesArgument(0, named("scala.Function1"))), + AkkaHttpAsyncAdvice.class.getName()); + return transformers; } public static class AkkaHttpSyncAdvice { diff --git a/dd-java-agent/instrumentation/apache-httpclient-4.3/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java b/dd-java-agent/instrumentation/apache-httpclient-4.3/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java index 6c3ff42d50..1efe58cd48 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-4.3/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java +++ b/dd-java-agent/instrumentation/apache-httpclient-4.3/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java @@ -5,49 +5,56 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.http.impl.client.DefaultRedirectStrategy; import org.apache.http.impl.execchain.ClientExecChain; @AutoService(Instrumenter.class) -public class ApacheHttpClientInstrumentation extends Instrumenter.Configurable { +public class ApacheHttpClientInstrumentation extends Instrumenter.Default { public ApacheHttpClientInstrumentation() { super("httpclient"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.http.impl.client.HttpClientBuilder"), - classLoaderHasClasses( - "org.apache.http.HttpException", - "org.apache.http.HttpRequest", - "org.apache.http.client.RedirectStrategy", - "org.apache.http.client.methods.CloseableHttpResponse", - "org.apache.http.client.methods.HttpExecutionAware", - "org.apache.http.client.methods.HttpRequestWrapper", - "org.apache.http.client.protocol.HttpClientContext", - "org.apache.http.conn.routing.HttpRoute", - "org.apache.http.impl.execchain.ClientExecChain")) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.apachehttpclient.DDTracingClientExec", - "datadog.trace.instrumentation.apachehttpclient.DDTracingClientExec$HttpHeadersInjectAdapter")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(named("decorateProtocolExec")), - ApacheHttpClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.http.impl.client.HttpClientBuilder"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "org.apache.http.HttpException", + "org.apache.http.HttpRequest", + "org.apache.http.client.RedirectStrategy", + "org.apache.http.client.methods.CloseableHttpResponse", + "org.apache.http.client.methods.HttpExecutionAware", + "org.apache.http.client.methods.HttpRequestWrapper", + "org.apache.http.client.protocol.HttpClientContext", + "org.apache.http.conn.routing.HttpRoute", + "org.apache.http.impl.execchain.ClientExecChain"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.apachehttpclient.DDTracingClientExec", + "datadog.trace.instrumentation.apachehttpclient.DDTracingClientExec$HttpHeadersInjectAdapter" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(named("decorateProtocolExec")), ApacheHttpClientAdvice.class.getName()); + return transformers; } public static class ApacheHttpClientAdvice { diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java index 226e9ff246..edb5e433c7 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java @@ -2,53 +2,59 @@ package datadog.trace.instrumentation.aws.v0; import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; import static net.bytebuddy.matcher.ElementMatchers.declaresField; -import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import com.amazonaws.handlers.RequestHandler2; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; +import java.util.HashMap; import java.util.List; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; /** * This instrumentation might work with versions before 1.11.0, but this was the first version that * is tested. It could possibly be extended earlier. */ @AutoService(Instrumenter.class) -public final class AWSClientInstrumentation extends Instrumenter.Configurable { +public final class AWSClientInstrumentation extends Instrumenter.Default { public AWSClientInstrumentation() { super("aws-sdk"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - isAbstract() - .and( - named("com.amazonaws.AmazonWebServiceClient") - .and(declaresField(named("requestHandler2s")))), - classLoaderHasClasses("com.amazonaws.http.client.HttpClientFactory") - .and( - not( - classLoaderHasClasses( - "com.amazonaws.client.builder.AwsClientBuilder$EndpointConfiguration")))) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.aws.v0.TracingRequestHandler", - "datadog.trace.instrumentation.aws.v0.SpanDecorator")) - .transform(DDTransformers.defaultTransformers()) - .transform(DDAdvice.create().advice(isConstructor(), AWSClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("com.amazonaws.AmazonWebServiceClient") + .and(declaresField(named("requestHandler2s"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("com.amazonaws.http.client.HttpClientFactory") + .and( + not( + classLoaderHasClasses( + "com.amazonaws.client.builder.AwsClientBuilder$EndpointConfiguration"))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.aws.v0.TracingRequestHandler", + "datadog.trace.instrumentation.aws.v0.SpanDecorator" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put(isConstructor(), AWSClientAdvice.class.getName()); + return transformers; } public static class AWSClientAdvice { diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.106/src/main/java/datadog/trace/instrumentation/aws/v106/AWSClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.106/src/main/java/datadog/trace/instrumentation/aws/v106/AWSClientInstrumentation.java index b5effae293..753e7d591d 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.106/src/main/java/datadog/trace/instrumentation/aws/v106/AWSClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.106/src/main/java/datadog/trace/instrumentation/aws/v106/AWSClientInstrumentation.java @@ -8,14 +8,13 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.amazonaws.handlers.RequestHandler2; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; +import java.util.HashMap; import java.util.List; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; /** * The interface for com.amazonaws.Request changed in 106. The method addHandlerContext which is @@ -23,28 +22,38 @@ import net.bytebuddy.asm.Advice; * bytecode compatible. The instrumentation is the same, but the compiled output is different. */ @AutoService(Instrumenter.class) -public final class AWSClientInstrumentation extends Instrumenter.Configurable { +public final class AWSClientInstrumentation extends Instrumenter.Default { public AWSClientInstrumentation() { super("aws-sdk"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - isAbstract() - .and( - named("com.amazonaws.AmazonWebServiceClient") - .and(declaresField(named("requestHandler2s")))), - classLoaderHasClasses("com.amazonaws.HandlerContextAware")) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.aws.v106.TracingRequestHandler", - "datadog.trace.instrumentation.aws.v106.SpanDecorator")) - .transform(DDTransformers.defaultTransformers()) - .transform(DDAdvice.create().advice(isConstructor(), AWSClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return isAbstract() + .and( + named("com.amazonaws.AmazonWebServiceClient") + .and(declaresField(named("requestHandler2s")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("com.amazonaws.HandlerContextAware"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.aws.v106.TracingRequestHandler", + "datadog.trace.instrumentation.aws.v106.SpanDecorator" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put(isConstructor(), AWSClientAdvice.class.getName()); + return transformers; } public static class AWSClientAdvice { diff --git a/dd-java-agent/instrumentation/classloaders/src/main/java/datadog/trace/instrumentation/classloaders/ClassLoaderInstrumentation.java b/dd-java-agent/instrumentation/classloaders/src/main/java/datadog/trace/instrumentation/classloaders/ClassLoaderInstrumentation.java index 0e526c2ef4..845bf8e5ae 100644 --- a/dd-java-agent/instrumentation/classloaders/src/main/java/datadog/trace/instrumentation/classloaders/ClassLoaderInstrumentation.java +++ b/dd-java-agent/instrumentation/classloaders/src/main/java/datadog/trace/instrumentation/classloaders/ClassLoaderInstrumentation.java @@ -1,23 +1,21 @@ package datadog.trace.instrumentation.classloaders; -import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; -import static net.bytebuddy.matcher.ElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf; import com.google.auto.service.AutoService; import datadog.opentracing.DDTracer; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Field; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class ClassLoaderInstrumentation extends Instrumenter.Configurable { +public final class ClassLoaderInstrumentation extends Instrumenter.Default { public ClassLoaderInstrumentation() { super("classloader"); @@ -29,14 +27,15 @@ public final class ClassLoaderInstrumentation extends Instrumenter.Configurable } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - failSafe(isSubTypeOf(ClassLoader.class)), - classLoaderHasClasses("io.opentracing.util.GlobalTracer")) - .transform(DDTransformers.defaultTransformers()) - .transform(DDAdvice.create().advice(isConstructor(), ClassloaderAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return isSubTypeOf(ClassLoader.class); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put(isConstructor(), ClassloaderAdvice.class.getName()); + return transformers; } public static class ClassloaderAdvice { @@ -60,6 +59,7 @@ public final class ClassLoaderInstrumentation extends Instrumenter.Configurable field.setAccessible(true); final Object o = field.get(null); + // FIXME: This instrumentation will never work. Referencing class DDTracer will throw an exception. if (o instanceof DDTracer) { final DDTracer tracer = (DDTracer) o; tracer.registerClassLoader(cl); diff --git a/dd-java-agent/instrumentation/datastax-cassandra-3.2/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientInstrumentation.java b/dd-java-agent/instrumentation/datastax-cassandra-3.2/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientInstrumentation.java index 446811b61d..ac24cc4472 100644 --- a/dd-java-agent/instrumentation/datastax-cassandra-3.2/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientInstrumentation.java +++ b/dd-java-agent/instrumentation/datastax-cassandra-3.2/src/main/java/datadog/trace/instrumentation/datastax/cassandra/CassandraClientInstrumentation.java @@ -8,41 +8,48 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.datastax.driver.core.Session; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.Tracer; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Constructor; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class CassandraClientInstrumentation extends Instrumenter.Configurable { +public class CassandraClientInstrumentation extends Instrumenter.Default { public CassandraClientInstrumentation() { super("cassandra"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("com.datastax.driver.core.Cluster$Manager"), - classLoaderHasClasses("com.datastax.driver.core.Duration")) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.datastax.cassandra.TracingSession", - "datadog.trace.instrumentation.datastax.cassandra.TracingSession$1", - "datadog.trace.instrumentation.datastax.cassandra.TracingSession$2")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPrivate()).and(named("newSession")).and(takesArguments(0)), - CassandraClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("com.datastax.driver.core.Cluster$Manager"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("com.datastax.driver.core.Duration"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.datastax.cassandra.TracingSession", + "datadog.trace.instrumentation.datastax.cassandra.TracingSession$1", + "datadog.trace.instrumentation.datastax.cassandra.TracingSession$2" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPrivate()).and(named("newSession")).and(takesArguments(0)), + CassandraClientAdvice.class.getName()); + return transformers; } public static class CassandraClientAdvice { diff --git a/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java index 3c2af1fdde..49e485b338 100644 --- a/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java @@ -10,8 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -19,12 +17,14 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.elasticsearch.client.ResponseListener; @AutoService(Instrumenter.class) -public class Elasticsearch5RestClientInstrumentation extends Instrumenter.Configurable { +public class Elasticsearch5RestClientInstrumentation extends Instrumenter.Default { public Elasticsearch5RestClientInstrumentation() { super("elasticsearch", "elasticsearch-rest", "elasticsearch-rest-5"); @@ -36,22 +36,23 @@ public class Elasticsearch5RestClientInstrumentation extends Instrumenter.Config } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(named("org.elasticsearch.client.RestClient"))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(named("performRequestAsync")) - .and(takesArguments(7)) - .and(takesArgument(0, named("java.lang.String"))) // method - .and(takesArgument(1, named("java.lang.String"))) // endpoint - .and(takesArgument(5, named("org.elasticsearch.client.ResponseListener"))), - ElasticsearchRestClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(named("org.elasticsearch.client.RestClient")); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("performRequestAsync")) + .and(takesArguments(7)) + .and(takesArgument(0, named("java.lang.String"))) // method + .and(takesArgument(1, named("java.lang.String"))) // endpoint + .and(takesArgument(5, named("org.elasticsearch.client.ResponseListener"))), + ElasticsearchRestClientAdvice.class.getName()); + return transformers; } public static class ElasticsearchRestClientAdvice { diff --git a/dd-java-agent/instrumentation/elasticsearch-transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch-transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java index 3b8eb12605..080774664a 100644 --- a/dd-java-agent/instrumentation/elasticsearch-transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch-transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java @@ -9,9 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -19,15 +16,17 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; @AutoService(Instrumenter.class) -public class Elasticsearch2TransportClientInstrumentation extends Instrumenter.Configurable { +public class Elasticsearch2TransportClientInstrumentation extends Instrumenter.Default { public Elasticsearch2TransportClientInstrumentation() { super("elasticsearch", "elasticsearch-transport", "elasticsearch-transport-2"); @@ -39,32 +38,40 @@ public class Elasticsearch2TransportClientInstrumentation extends Instrumenter.C } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")), - // If we want to be more generic, we could instrument the interface instead: - // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - classLoaderHasClasses("org.elasticsearch.plugins.SitePlugin")) - .transform( - new HelperInjector( - "com.google.common.base.Preconditions", - "com.google.common.base.Joiner", - "com.google.common.base.Joiner$1", - "com.google.common.base.Joiner$2", - "com.google.common.base.Joiner$MapJoiner", - "datadog.trace.instrumentation.elasticsearch2.TransportActionListener")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(named("execute")) - .and(takesArgument(0, named("org.elasticsearch.action.Action"))) - .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) - .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), - ElasticsearchTransportClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + // If we want to be more generic, we could instrument the interface instead: + // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) + return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.elasticsearch.plugins.SitePlugin"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "com.google.common.base.Preconditions", + "com.google.common.base.Joiner", + "com.google.common.base.Joiner$1", + "com.google.common.base.Joiner$2", + "com.google.common.base.Joiner$MapJoiner", + "datadog.trace.instrumentation.elasticsearch2.TransportActionListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("execute")) + .and(takesArgument(0, named("org.elasticsearch.action.Action"))) + .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) + .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), + ElasticsearchTransportClientAdvice.class.getName()); + return transformers; } public static class ElasticsearchTransportClientAdvice { diff --git a/dd-java-agent/instrumentation/elasticsearch-transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch-transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java index 5554787e0b..495223eba8 100644 --- a/dd-java-agent/instrumentation/elasticsearch-transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch-transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java @@ -9,9 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -19,15 +16,17 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; @AutoService(Instrumenter.class) -public class Elasticsearch5TransportClientInstrumentation extends Instrumenter.Configurable { +public class Elasticsearch5TransportClientInstrumentation extends Instrumenter.Default { public Elasticsearch5TransportClientInstrumentation() { super("elasticsearch", "elasticsearch-transport", "elasticsearch-transport-5"); @@ -39,32 +38,40 @@ public class Elasticsearch5TransportClientInstrumentation extends Instrumenter.C } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")), - // If we want to be more generic, we could instrument the interface instead: - // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - classLoaderHasClasses("org.elasticsearch.percolator.TransportMultiPercolateAction")) - .transform( - new HelperInjector( - "com.google.common.base.Preconditions", - "com.google.common.base.Joiner", - "com.google.common.base.Joiner$1", - "com.google.common.base.Joiner$2", - "com.google.common.base.Joiner$MapJoiner", - "datadog.trace.instrumentation.elasticsearch5.TransportActionListener")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(named("execute")) - .and(takesArgument(0, named("org.elasticsearch.action.Action"))) - .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) - .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), - ElasticsearchTransportClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + // If we want to be more generic, we could instrument the interface instead: + // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) + return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.elasticsearch.percolator.TransportMultiPercolateAction"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "com.google.common.base.Preconditions", + "com.google.common.base.Joiner", + "com.google.common.base.Joiner$1", + "com.google.common.base.Joiner$2", + "com.google.common.base.Joiner$MapJoiner", + "datadog.trace.instrumentation.elasticsearch5.TransportActionListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("execute")) + .and(takesArgument(0, named("org.elasticsearch.action.Action"))) + .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) + .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), + ElasticsearchTransportClientAdvice.class.getName()); + return transformers; } public static class ElasticsearchTransportClientAdvice { diff --git a/dd-java-agent/instrumentation/elasticsearch-transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch-transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java index d82515f0b3..b223b7080d 100644 --- a/dd-java-agent/instrumentation/elasticsearch-transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch-transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java @@ -9,9 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -19,8 +16,10 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; @@ -31,7 +30,7 @@ import org.elasticsearch.action.ActionResponse; * an abstract class, so the bytecode isn't directly compatible. */ @AutoService(Instrumenter.class) -public class Elasticsearch6TransportClientInstrumentation extends Instrumenter.Configurable { +public class Elasticsearch6TransportClientInstrumentation extends Instrumenter.Default { public Elasticsearch6TransportClientInstrumentation() { super("elasticsearch", "elasticsearch-transport", "elasticsearch-transport-6"); @@ -43,32 +42,40 @@ public class Elasticsearch6TransportClientInstrumentation extends Instrumenter.C } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")), - // If we want to be more generic, we could instrument the interface instead: - // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - classLoaderHasClasses("org.elasticsearch.client.RestClientBuilder$2")) - .transform( - new HelperInjector( - "com.google.common.base.Preconditions", - "com.google.common.base.Joiner", - "com.google.common.base.Joiner$1", - "com.google.common.base.Joiner$2", - "com.google.common.base.Joiner$MapJoiner", - "datadog.trace.instrumentation.elasticsearch6.TransportActionListener")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(named("execute")) - .and(takesArgument(0, named("org.elasticsearch.action.Action"))) - .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) - .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), - Elasticsearch6TransportClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + // If we want to be more generic, we could instrument the interface instead: + // .and(hasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) + return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.elasticsearch.client.RestClientBuilder$2"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "com.google.common.base.Preconditions", + "com.google.common.base.Joiner", + "com.google.common.base.Joiner$1", + "com.google.common.base.Joiner$2", + "com.google.common.base.Joiner$MapJoiner", + "datadog.trace.instrumentation.elasticsearch6.TransportActionListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("execute")) + .and(takesArgument(0, named("org.elasticsearch.action.Action"))) + .and(takesArgument(1, named("org.elasticsearch.action.ActionRequest"))) + .and(takesArgument(2, named("org.elasticsearch.action.ActionListener"))), + Elasticsearch6TransportClientAdvice.class.getName()); + return transformers; } public static class Elasticsearch6TransportClientAdvice { diff --git a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java index b743b018f6..875b8c09eb 100644 --- a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java @@ -8,9 +8,6 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,12 +21,14 @@ import io.opentracing.util.GlobalTracer; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.net.ssl.HttpsURLConnection; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class HttpUrlConnectionInstrumentation extends Instrumenter.Configurable { +public class HttpUrlConnectionInstrumentation extends Instrumenter.Default { public HttpUrlConnectionInstrumentation() { super("httpurlconnection"); @@ -41,25 +40,30 @@ public class HttpUrlConnectionInstrumentation extends Instrumenter.Configurable } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(isSubTypeOf(HttpURLConnection.class)) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.http_url_connection.MessageHeadersInjectAdapter")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and( - named("getResponseCode") - .or(named("getOutputStream")) - .or(named("getInputStream")) - .or(nameStartsWith("getHeaderField"))), - HttpUrlConnectionAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return isSubTypeOf(HttpURLConnection.class); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.http_url_connection.MessageHeadersInjectAdapter" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and( + named("getResponseCode") + .or(named("getOutputStream")) + .or(named("getInputStream")) + .or(nameStartsWith("getHeaderField"))), + HttpUrlConnectionAdvice.class.getName()); + return transformers; } public static class HttpUrlConnectionAdvice { diff --git a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java index 8ddada8d54..f71e3d5e87 100644 --- a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java +++ b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java @@ -7,8 +7,6 @@ import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -18,11 +16,13 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.net.URL; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class UrlInstrumentation extends Instrumenter.Configurable { +public class UrlInstrumentation extends Instrumenter.Default { public UrlInstrumentation() { super("urlconnection", "httpurlconnection"); @@ -34,16 +34,17 @@ public class UrlInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(is(URL.class)) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPublic()).and(named("openConnection")), - ConnectionErrorAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return is(URL.class); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPublic()).and(named("openConnection")), + ConnectionErrorAdvice.class.getName()); + return transformers; } public static class ConnectionErrorAdvice { diff --git a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixCommandInstrumentation.java b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixCommandInstrumentation.java index 690d025965..fa56b6261b 100644 --- a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixCommandInstrumentation.java +++ b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixCommandInstrumentation.java @@ -8,37 +8,35 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Method; -import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.*; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class HystrixCommandInstrumentation extends Instrumenter.Configurable { +public class HystrixCommandInstrumentation extends Instrumenter.Default { public HystrixCommandInstrumentation() { super("hystrix"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(hasSuperType(named("com.netflix.hystrix.HystrixCommand")))) - // Not adding a version restriction because this should work with any version and add some benefit. - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(named("run").or(named("getFallback"))), - TraceAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + // Not adding a version restriction because this should work with any version and add some benefit. + return not(isInterface()).and(hasSuperType(named("com.netflix.hystrix.HystrixCommand"))); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(named("run").or(named("getFallback"))), TraceAdvice.class.getName()); + return transformers; } public static class TraceAdvice { diff --git a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixThreadPoolInstrumentation.java b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixThreadPoolInstrumentation.java index b2d6c3ea94..f4fd053cb6 100644 --- a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixThreadPoolInstrumentation.java +++ b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixThreadPoolInstrumentation.java @@ -6,36 +6,39 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.context.TraceScope; import io.opentracing.Scope; import io.opentracing.util.GlobalTracer; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.*; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class HystrixThreadPoolInstrumentation extends Instrumenter.Configurable { +public class HystrixThreadPoolInstrumentation extends Instrumenter.Default { public HystrixThreadPoolInstrumentation() { super("hystrix"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named( - "com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler$ThreadPoolWorker"), - classLoaderHasClasses("com.netflix.hystrix.AbstractCommand")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(named("schedule")).and(takesArguments(1)), - EnableAsyncAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named( + "com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler$ThreadPoolWorker"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("com.netflix.hystrix.AbstractCommand"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(named("schedule")).and(takesArguments(1)), + EnableAsyncAdvice.class.getName()); + return transformers; } public static class EnableAsyncAdvice { diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ExecutorInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ExecutorInstrumentation.java index 40ecf1a329..8aa2535dd6 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ExecutorInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ExecutorInstrumentation.java @@ -8,42 +8,27 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; -import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.*; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.context.TraceScope; import io.opentracing.Scope; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @Slf4j @AutoService(Instrumenter.class) -public final class ExecutorInstrumentation extends Instrumenter.Configurable { +public final class ExecutorInstrumentation extends Instrumenter.Default { public static final String EXEC_NAME = "java_concurrent"; - public static final HelperInjector EXEC_HELPER_INJECTOR = - new HelperInjector( - ExecutorInstrumentation.class.getName() + "$ConcurrentUtils", - ExecutorInstrumentation.class.getName() + "$DatadogWrapper", - ExecutorInstrumentation.class.getName() + "$CallableWrapper", - ExecutorInstrumentation.class.getName() + "$RunnableWrapper"); /** * Only apply executor instrumentation to whitelisted executors. In the future, this restriction @@ -102,9 +87,9 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(hasSuperType(named(Executor.class.getName())))) + public ElementMatcher typeMatcher() { + return not(isInterface()) + .and(hasSuperType(named(Executor.class.getName()))) .and( new ElementMatcher() { @Override @@ -126,34 +111,32 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable { } return whitelisted; } - }) - .transform(EXEC_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("execute").and(takesArgument(0, Runnable.class)), - WrapRunnableAdvice.class.getName())) - .asDecorator() - .type(not(isInterface()).and(hasSuperType(named(ExecutorService.class.getName())))) - .transform(EXEC_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("submit").and(takesArgument(0, Runnable.class)), - WrapRunnableAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - named("submit").and(takesArgument(0, Callable.class)), - WrapCallableAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - nameMatches("invoke(Any|All)$").and(takesArgument(0, Callable.class)), - WrapCallableCollectionAdvice.class.getName())) - .asDecorator(); + }); + } + + @Override + public String[] helperClassNames() { + return new String[] { + ExecutorInstrumentation.class.getName() + "$ConcurrentUtils", + ExecutorInstrumentation.class.getName() + "$DatadogWrapper", + ExecutorInstrumentation.class.getName() + "$CallableWrapper", + ExecutorInstrumentation.class.getName() + "$RunnableWrapper" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("execute").and(takesArgument(0, Runnable.class)), WrapRunnableAdvice.class.getName()); + transformers.put( + named("submit").and(takesArgument(0, Runnable.class)), WrapRunnableAdvice.class.getName()); + transformers.put( + named("submit").and(takesArgument(0, Callable.class)), WrapCallableAdvice.class.getName()); + transformers.put( + nameMatches("invoke(Any|All)$").and(takesArgument(0, Callable.class)), + WrapCallableCollectionAdvice.class.getName()); + return transformers; } public static class WrapRunnableAdvice { diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java index eb21c2af36..0471b38d3c 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java @@ -7,25 +7,19 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.instrumentation.java.concurrent.ExecutorInstrumentation.ConcurrentUtils; import datadog.trace.instrumentation.java.concurrent.ExecutorInstrumentation.DatadogWrapper; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; +import java.util.*; import java.util.concurrent.Future; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @Slf4j @AutoService(Instrumenter.class) -public final class FutureInstrumentation extends Instrumenter.Configurable { +public final class FutureInstrumentation extends Instrumenter.Default { /** * Only apply executor instrumentation to whitelisted executors. In the future, this restriction @@ -69,9 +63,9 @@ public final class FutureInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(hasSuperType(named(Future.class.getName())))) + public ElementMatcher typeMatcher() { + return not(isInterface()) + .and(hasSuperType(named(Future.class.getName()))) .and( new ElementMatcher() { @Override @@ -82,15 +76,25 @@ public final class FutureInstrumentation extends Instrumenter.Configurable { } return whitelisted; } - }) - .transform(ExecutorInstrumentation.EXEC_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("cancel").and(returns(boolean.class)), - CanceledFutureAdvice.class.getName())) - .asDecorator(); + }); + } + + @Override + public String[] helperClassNames() { + return new String[] { + ExecutorInstrumentation.class.getName() + "$ConcurrentUtils", + ExecutorInstrumentation.class.getName() + "$DatadogWrapper", + ExecutorInstrumentation.class.getName() + "$CallableWrapper", + ExecutorInstrumentation.class.getName() + "$RunnableWrapper" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("cancel").and(returns(boolean.class)), CanceledFutureAdvice.class.getName()); + return transformers; } public static class CanceledFutureAdvice { diff --git a/dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java index 3b9f241c2d..9598fb539b 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java @@ -7,8 +7,6 @@ import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -16,43 +14,42 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.LinkedList; +import java.util.*; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Configurable { +public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default { public JaxRsAnnotationsInstrumentation() { super("jax-rs", "jaxrs", "jax-rs-annotations"); } @Override - protected AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - hasSuperType( - isAnnotatedWith(named("javax.ws.rs.Path")) - .or( - failSafe( - hasSuperType( - declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path")))))))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isAnnotatedWith( - named("javax.ws.rs.Path") - .or(named("javax.ws.rs.DELETE")) - .or(named("javax.ws.rs.GET")) - .or(named("javax.ws.rs.HEAD")) - .or(named("javax.ws.rs.OPTIONS")) - .or(named("javax.ws.rs.POST")) - .or(named("javax.ws.rs.PUT"))), - JaxRsAnnotationsAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return hasSuperType( + isAnnotatedWith(named("javax.ws.rs.Path")) + .or( + failSafe( + hasSuperType(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path"))))))); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isAnnotatedWith( + named("javax.ws.rs.Path") + .or(named("javax.ws.rs.DELETE")) + .or(named("javax.ws.rs.GET")) + .or(named("javax.ws.rs.HEAD")) + .or(named("javax.ws.rs.OPTIONS")) + .or(named("javax.ws.rs.POST")) + .or(named("javax.ws.rs.PUT"))), + JaxRsAnnotationsAdvice.class.getName()); + return transformers; } public static class JaxRsAnnotationsAdvice { diff --git a/dd-java-agent/instrumentation/jax-rs-client/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-client/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java index 4e48c7fef0..9dc0193a32 100644 --- a/dd-java-agent/instrumentation/jax-rs-client/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-client/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java @@ -6,37 +6,41 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; -import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.*; +import java.util.HashMap; +import java.util.Map; import javax.ws.rs.client.ClientBuilder; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JaxRsClientInstrumentation extends Instrumenter.Configurable { +public final class JaxRsClientInstrumentation extends Instrumenter.Default { public JaxRsClientInstrumentation() { super("jax-rs", "jaxrs", "jax-rs-client"); } @Override - protected AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(failSafe(hasSuperType(named("javax.ws.rs.client.ClientBuilder")))) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.jaxrs.ClientTracingFeature", - "datadog.trace.instrumentation.jaxrs.ClientTracingFilter", - "datadog.trace.instrumentation.jaxrs.InjectAdapter")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("build").and(returns(hasSuperType(named("javax.ws.rs.client.Client")))), - ClientBuilderAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return failSafe(hasSuperType(named("javax.ws.rs.client.ClientBuilder"))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.jaxrs.ClientTracingFeature", + "datadog.trace.instrumentation.jaxrs.ClientTracingFilter", + "datadog.trace.instrumentation.jaxrs.InjectAdapter" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("build").and(returns(hasSuperType(named("javax.ws.rs.client.Client")))), + ClientBuilderAdvice.class.getName()); + return transformers; } public static class ClientBuilderAdvice { diff --git a/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java b/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java index 01a23f3ccb..6190dfa646 100644 --- a/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java +++ b/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java @@ -1,56 +1,52 @@ package datadog.trace.instrumentation.jboss; -import static net.bytebuddy.matcher.ElementMatchers.named; - import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Utils; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.utility.JavaModule; +import java.util.Collections; +import java.util.Map; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.NameMatcher; +import net.bytebuddy.matcher.StringMatcher; @AutoService(Instrumenter.class) -public final class JBossClassloadingInstrumentation extends Instrumenter.Configurable { +public final class JBossClassloadingInstrumentation extends Instrumenter.Default { public JBossClassloadingInstrumentation() { super("jboss-classloading"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - // Jboss Module class loads the sys prop which defines bootstrap classes - .type(named("org.jboss.modules.Module")) - .transform(DDTransformers.defaultTransformers()) - .transform( - new AgentBuilder.Transformer() { - @Override - public DynamicType.Builder transform( - DynamicType.Builder builder, - TypeDescription typeDescription, - ClassLoader classLoader, - JavaModule javaModule) { - // This instrumentation modifies no bytes. - // Instead it sets a system prop to tell jboss to delegate - // classloads for datadog bootstrap classes - StringBuilder ddPrefixes = new StringBuilder(""); - for (int i = 0; i < Utils.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { - if (i > 0) { - ddPrefixes.append(","); - } - ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]); + public ElementMatcher typeMatcher() { + return new NameMatcher( + new StringMatcher("org.jboss.modules.Module", StringMatcher.Mode.EQUALS_FULLY) { + @Override + public boolean matches(String target) { + if (super.matches(target)) { + // This instrumentation modifies no bytes. + // Instead it sets a system prop to tell jboss to delegate + // classloads for datadog bootstrap classes + StringBuilder ddPrefixes = new StringBuilder(""); + for (int i = 0; i < Utils.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { + if (i > 0) { + ddPrefixes.append(","); } - final String existing = System.getProperty("jboss.modules.system.pkgs"); - if (null == existing) { - System.setProperty("jboss.modules.system.pkgs", ddPrefixes.toString()); - } else if (!existing.contains(ddPrefixes)) { - System.setProperty( - "jboss.modules.system.pkgs", existing + "," + ddPrefixes.toString()); - } - return builder; + ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]); } - }) - .asDecorator(); + final String existing = System.getProperty("jboss.modules.system.pkgs"); + if (null == existing) { + System.setProperty("jboss.modules.system.pkgs", ddPrefixes.toString()); + } else if (!existing.contains(ddPrefixes)) { + System.setProperty( + "jboss.modules.system.pkgs", existing + "," + ddPrefixes.toString()); + } + } + return false; + } + }); + } + + @Override + public Map transformers() { + return Collections.emptyMap(); } } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java index f530387627..e5c21a4c70 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java @@ -9,35 +9,36 @@ import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.JDBCMaps; import java.sql.Connection; import java.sql.PreparedStatement; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class ConnectionInstrumentation extends Instrumenter.Configurable { +public final class ConnectionInstrumentation extends Instrumenter.Default { public ConnectionInstrumentation() { super("jdbc"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(failSafe(isSubTypeOf(Connection.class)))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - nameStartsWith("prepare") - .and(takesArgument(0, String.class)) - .and(returns(PreparedStatement.class)), - ConnectionPrepareAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(isSubTypeOf(Connection.class))); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + nameStartsWith("prepare") + .and(takesArgument(0, String.class)) + .and(returns(PreparedStatement.class)), + ConnectionPrepareAdvice.class.getName()); + return transformers; } public static class ConnectionPrepareAdvice { diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java index 32fd3501ad..33f0a3c456 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -1,7 +1,6 @@ package datadog.trace.instrumentation.jdbc; import static io.opentracing.log.Fields.ERROR_OBJECT; -import static net.bytebuddy.matcher.ElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf; @@ -10,8 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import datadog.trace.bootstrap.CallDepthThreadLocalMap; @@ -25,26 +22,29 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class PreparedStatementInstrumentation extends Instrumenter.Configurable { +public final class PreparedStatementInstrumentation extends Instrumenter.Default { public PreparedStatementInstrumentation() { super("jdbc"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(failSafe(isSubTypeOf(PreparedStatement.class)))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - nameStartsWith("execute").and(takesArguments(0)).and(isPublic()), - PreparedStatementAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(isSubTypeOf(PreparedStatement.class)); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + nameStartsWith("execute").and(takesArguments(0)).and(isPublic()), + PreparedStatementAdvice.class.getName()); + return transformers; } public static class PreparedStatementAdvice { diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index 61790f4d83..bf40bfdd11 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -1,7 +1,6 @@ package datadog.trace.instrumentation.jdbc; import static io.opentracing.log.Fields.ERROR_OBJECT; -import static net.bytebuddy.matcher.ElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf; @@ -10,8 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import datadog.trace.bootstrap.CallDepthThreadLocalMap; @@ -25,27 +22,30 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class StatementInstrumentation extends Instrumenter.Configurable { +public final class StatementInstrumentation extends Instrumenter.Default { public StatementInstrumentation() { super("jdbc"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(failSafe(isSubTypeOf(Statement.class)))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - nameStartsWith("execute").and(takesArgument(0, String.class)).and(isPublic()), - StatementAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(isSubTypeOf(Statement.class)); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + nameStartsWith("execute").and(takesArgument(0, String.class)).and(isPublic()), + StatementAdvice.class.getName()); + return transformers; } public static class StatementAdvice { diff --git a/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java b/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java index ebf704479c..7dca92ec21 100644 --- a/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java +++ b/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java @@ -7,8 +7,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; @@ -16,12 +14,14 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import redis.clients.jedis.Protocol.Command; @AutoService(Instrumenter.class) -public final class JedisInstrumentation extends Instrumenter.Configurable { +public final class JedisInstrumentation extends Instrumenter.Default { private static final String SERVICE_NAME = "redis"; private static final String COMPONENT_NAME = SERVICE_NAME + "-command"; @@ -31,21 +31,30 @@ public final class JedisInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("redis.clients.jedis.Protocol"), - classLoaderHasClasses("redis.clients.jedis.Protocol$Command")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(named("sendCommand")) - .and(takesArgument(1, named("redis.clients.jedis.Protocol$Command"))), - JedisAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("redis.clients.jedis.Protocol"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("redis.clients.jedis.Protocol$Command"); + } + + @Override + public String[] helperClassNames() { + return new String[] {}; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("sendCommand")) + .and(takesArgument(1, named("redis.clients.jedis.Protocol$Command"))), + JedisAdvice.class.getName()); + return transformers; } public static class JedisAdvice { diff --git a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/HandlerInstrumentation.java b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/HandlerInstrumentation.java index 611d106e2e..471bf6dd7e 100644 --- a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/HandlerInstrumentation.java +++ b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/HandlerInstrumentation.java @@ -10,8 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,16 +22,18 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class HandlerInstrumentation extends Instrumenter.Configurable { +public final class HandlerInstrumentation extends Instrumenter.Default { public static final String SERVLET_OPERATION_NAME = "jetty.request"; public HandlerInstrumentation() { @@ -46,29 +46,38 @@ public final class HandlerInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()) - .and(hasSuperType(named("org.eclipse.jetty.server.Handler"))) - .and(not(named("org.eclipse.jetty.server.handler.HandlerWrapper"))), - not(classLoaderHasClasses("org.eclipse.jetty.server.AsyncContext"))) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.jetty8.HttpServletRequestExtractAdapter", - "datadog.trace.instrumentation.jetty8.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", - HandlerInstrumentationAdvice.class.getName() + "$TagSettingAsyncListener")) - .transform( - DDAdvice.create() - .advice( - named("handle") - .and(takesArgument(0, named("java.lang.String"))) - .and(takesArgument(1, named("org.eclipse.jetty.server.Request"))) - .and(takesArgument(2, named("javax.servlet.http.HttpServletRequest"))) - .and(takesArgument(3, named("javax.servlet.http.HttpServletResponse"))) - .and(isPublic()), - HandlerInstrumentationAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()) + .and(hasSuperType(named("org.eclipse.jetty.server.Handler"))) + .and(not(named("org.eclipse.jetty.server.handler.HandlerWrapper"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("org.eclipse.jetty.server.AsyncContext")); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.jetty8.HttpServletRequestExtractAdapter", + "datadog.trace.instrumentation.jetty8.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", + HandlerInstrumentationAdvice.class.getName() + "$TagSettingAsyncListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("handle") + .and(takesArgument(0, named("java.lang.String"))) + .and(takesArgument(1, named("org.eclipse.jetty.server.Request"))) + .and(takesArgument(2, named("javax.servlet.http.HttpServletRequest"))) + .and(takesArgument(3, named("javax.servlet.http.HttpServletResponse"))) + .and(isPublic()), + HandlerInstrumentationAdvice.class.getName()); + return transformers; } public static class HandlerInstrumentationAdvice { diff --git a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageConsumerInstrumentation.java b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageConsumerInstrumentation.java index bcac11693d..1b6d6ce48c 100644 --- a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageConsumerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageConsumerInstrumentation.java @@ -3,7 +3,6 @@ package datadog.trace.instrumentation.jms1; import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; import static datadog.trace.instrumentation.jms.util.JmsUtil.toResourceName; import static io.opentracing.log.Fields.ERROR_OBJECT; -import static net.bytebuddy.matcher.ElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; @@ -12,10 +11,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; -import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.*; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap; @@ -27,41 +23,51 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Method; -import java.util.Collections; +import java.util.*; import java.util.concurrent.TimeUnit; import javax.jms.Message; import javax.jms.MessageConsumer; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS1MessageConsumerInstrumentation extends Instrumenter.Configurable { - public static final HelperInjector JMS1_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.jms.util.JmsUtil", - "datadog.trace.instrumentation.jms.util.MessagePropertyTextMap"); +public final class JMS1MessageConsumerInstrumentation extends Instrumenter.Default { + public static final String[] JMS1_HELPER_CLASS_NAMES = + new String[] { + "datadog.trace.instrumentation.jms.util.JmsUtil", + "datadog.trace.instrumentation.jms.util.MessagePropertyTextMap" + }; public JMS1MessageConsumerInstrumentation() { super("jms", "jms-1"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageConsumer")))), - not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))) - .transform(JMS1_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("receive").and(takesArguments(0).or(takesArguments(1))).and(isPublic()), - ConsumerAdvice.class.getName()) - .advice( - named("receiveNoWait").and(takesArguments(0)).and(isPublic()), - ConsumerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("javax.jms.MessageConsumer"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")); + } + + @Override + public String[] helperClassNames() { + return JMS1_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("receive").and(takesArguments(0).or(takesArguments(1))).and(isPublic()), + ConsumerAdvice.class.getName()); + transformers.put( + named("receiveNoWait").and(takesArguments(0)).and(isPublic()), + ConsumerAdvice.class.getName()); + return transformers; } public static class ConsumerAdvice { diff --git a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageListenerInstrumentation.java b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageListenerInstrumentation.java index 207b043ba5..c8837ed721 100644 --- a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageListenerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageListenerInstrumentation.java @@ -12,8 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -26,34 +24,42 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.jms.Message; import javax.jms.MessageListener; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS1MessageListenerInstrumentation extends Instrumenter.Configurable { +public final class JMS1MessageListenerInstrumentation extends Instrumenter.Default { public JMS1MessageListenerInstrumentation() { super("jms", "jms-1"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageListener")))), - not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))) - .transform(JMS1MessageConsumerInstrumentation.JMS1_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("onMessage") - .and(takesArgument(0, named("javax.jms.Message"))) - .and(isPublic()), - MessageListenerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageListener")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")); + } + + @Override + public String[] helperClassNames() { + return JMS1MessageConsumerInstrumentation.JMS1_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("onMessage").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), + MessageListenerAdvice.class.getName()); + return transformers; } public static class MessageListenerAdvice { diff --git a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageProducerInstrumentation.java b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageProducerInstrumentation.java index 062e61cdda..9cb37ff2b5 100644 --- a/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageProducerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-1/src/main/java/datadog/trace/instrumentation/jms1/JMS1MessageProducerInstrumentation.java @@ -12,8 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,40 +22,50 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageProducer; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS1MessageProducerInstrumentation extends Instrumenter.Configurable { +public final class JMS1MessageProducerInstrumentation extends Instrumenter.Default { public JMS1MessageProducerInstrumentation() { super("jms", "jms-1"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageProducer")))), - not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))) - .transform(JMS1MessageConsumerInstrumentation.JMS1_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), - ProducerAdvice.class.getName()) - .advice( - named("send") - .and(takesArgument(0, named("javax.jms.Destination"))) - .and(takesArgument(1, named("javax.jms.Message"))) - .and(isPublic()), - ProducerWithDestinationAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageProducer")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")); + } + + @Override + public String[] helperClassNames() { + return JMS1MessageConsumerInstrumentation.JMS1_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), + ProducerAdvice.class.getName()); + transformers.put( + named("send") + .and(takesArgument(0, named("javax.jms.Destination"))) + .and(takesArgument(1, named("javax.jms.Message"))) + .and(isPublic()), + ProducerWithDestinationAdvice.class.getName()); + return transformers; } public static class ProducerAdvice { diff --git a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageConsumerInstrumentation.java b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageConsumerInstrumentation.java index d962c65adf..73e9d86571 100644 --- a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageConsumerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageConsumerInstrumentation.java @@ -12,9 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -28,40 +25,51 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Method; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; import javax.jms.Message; import javax.jms.MessageConsumer; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS2MessageConsumerInstrumentation extends Instrumenter.Configurable { - public static final HelperInjector JMS2_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.jms.util.JmsUtil", - "datadog.trace.instrumentation.jms.util.MessagePropertyTextMap"); +public final class JMS2MessageConsumerInstrumentation extends Instrumenter.Default { + public static final String[] JMS2_HELPER_CLASS_NAMES = + new String[] { + "datadog.trace.instrumentation.jms.util.JmsUtil", + "datadog.trace.instrumentation.jms.util.MessagePropertyTextMap" + }; public JMS2MessageConsumerInstrumentation() { super("jms", "jms-2"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageConsumer")))), - classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")) - .transform(JMS2_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("receive").and(takesArguments(0).or(takesArguments(1))).and(isPublic()), - ConsumerAdvice.class.getName()) - .advice( - named("receiveNoWait").and(takesArguments(0)).and(isPublic()), - ConsumerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageConsumer")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"); + } + + @Override + public String[] helperClassNames() { + return JMS2_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("receive").and(takesArguments(0).or(takesArguments(1))).and(isPublic()), + ConsumerAdvice.class.getName()); + transformers.put( + named("receiveNoWait").and(takesArguments(0)).and(isPublic()), + ConsumerAdvice.class.getName()); + return transformers; } public static class ConsumerAdvice { diff --git a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageListenerInstrumentation.java b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageListenerInstrumentation.java index d77721e18b..5d457f25a4 100644 --- a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageListenerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageListenerInstrumentation.java @@ -12,8 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -26,34 +24,42 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.jms.Message; import javax.jms.MessageListener; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS2MessageListenerInstrumentation extends Instrumenter.Configurable { +public final class JMS2MessageListenerInstrumentation extends Instrumenter.Default { public JMS2MessageListenerInstrumentation() { super("jms", "jms-2"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageListener")))), - classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")) - .transform(JMS2MessageConsumerInstrumentation.JMS2_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("onMessage") - .and(takesArgument(0, named("javax.jms.Message"))) - .and(isPublic()), - MessageListenerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageListener")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"); + } + + @Override + public String[] helperClassNames() { + return JMS2MessageConsumerInstrumentation.JMS2_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("onMessage").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), + MessageListenerAdvice.class.getName()); + return transformers; } public static class MessageListenerAdvice { diff --git a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageProducerInstrumentation.java b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageProducerInstrumentation.java index e607e43c6b..f8d41483e4 100644 --- a/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageProducerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms-2/src/main/java/datadog/trace/instrumentation/jms2/JMS2MessageProducerInstrumentation.java @@ -12,8 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,40 +22,50 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageProducer; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JMS2MessageProducerInstrumentation extends Instrumenter.Configurable { +public final class JMS2MessageProducerInstrumentation extends Instrumenter.Default { public JMS2MessageProducerInstrumentation() { super("jms", "jms-2"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageProducer")))), - classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")) - .transform(JMS2MessageConsumerInstrumentation.JMS2_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), - ProducerAdvice.class.getName()) - .advice( - named("send") - .and(takesArgument(0, named("javax.jms.Destination"))) - .and(takesArgument(1, named("javax.jms.Message"))) - .and(isPublic()), - ProducerWithDestinationAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.jms.MessageProducer")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"); + } + + @Override + public String[] helperClassNames() { + return JMS2MessageConsumerInstrumentation.JMS2_HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()), + ProducerAdvice.class.getName()); + transformers.put( + named("send") + .and(takesArgument(0, named("javax.jms.Destination"))) + .and(takesArgument(1, named("javax.jms.Message"))) + .and(isPublic()), + ProducerWithDestinationAdvice.class.getName()); + return transformers; } public static class ProducerAdvice { diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java index 6094bcc21e..4405b4f721 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java +++ b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java @@ -4,8 +4,6 @@ import static io.opentracing.log.Fields.ERROR_OBJECT; import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -14,14 +12,16 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class JSPInstrumentation extends Instrumenter.Configurable { +public final class JSPInstrumentation extends Instrumenter.Default { public JSPInstrumentation() { super("jsp", "jsp-render"); @@ -33,19 +33,20 @@ public final class JSPInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(not(isInterface()).and(hasSuperType(named("javax.servlet.jsp.HttpJspPage")))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("_jspService") - .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) - .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) - .and(isPublic()), - HttpJspPageAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("javax.servlet.jsp.HttpJspPage"))); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("_jspService") + .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) + .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) + .and(isPublic()), + HttpJspPageAdvice.class.getName()); + return transformers; } public static class HttpJspPageAdvice { diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JasperJSPCompilationContextInstrumentation.java b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JasperJSPCompilationContextInstrumentation.java index 6c94c61ca2..e84af1ced5 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JasperJSPCompilationContextInstrumentation.java +++ b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JasperJSPCompilationContextInstrumentation.java @@ -5,8 +5,6 @@ import static io.opentracing.log.Fields.ERROR_OBJECT; import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -15,12 +13,14 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.jasper.JspCompilationContext; @AutoService(Instrumenter.class) -public final class JasperJSPCompilationContextInstrumentation extends Instrumenter.Configurable { +public final class JasperJSPCompilationContextInstrumentation extends Instrumenter.Default { public JasperJSPCompilationContextInstrumentation() { super("jsp", "jsp-compile"); @@ -32,18 +32,22 @@ public final class JasperJSPCompilationContextInstrumentation extends Instrument } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.jasper.JspCompilationContext"), - classLoaderHasClasses("org.apache.jasper.servlet.JspServletWrapper")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("compile").and(takesArguments(0)).and(isPublic()), - JasperJspCompilationContext.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.jasper.JspCompilationContext"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.apache.jasper.servlet.JspServletWrapper"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("compile").and(takesArguments(0)).and(isPublic()), + JasperJspCompilationContext.class.getName()); + return transformers; } public static class JasperJspCompilationContext { diff --git a/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaConsumerInstrumentation.java b/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaConsumerInstrumentation.java index d1967c8ba9..0186ec8fb8 100644 --- a/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaConsumerInstrumentation.java +++ b/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaConsumerInstrumentation.java @@ -9,9 +9,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -20,51 +17,62 @@ import io.opentracing.Tracer; import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; +import java.util.HashMap; import java.util.Iterator; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.kafka.clients.consumer.ConsumerRecord; @AutoService(Instrumenter.class) -public final class KafkaConsumerInstrumentation extends Instrumenter.Configurable { - public static final HelperInjector HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.kafka_clients.TextMapExtractAdapter", - "datadog.trace.instrumentation.kafka_clients.TracingIterable", - "datadog.trace.instrumentation.kafka_clients.TracingIterable$TracingIterator", - "datadog.trace.instrumentation.kafka_clients.TracingIterable$SpanBuilderDecorator", - "datadog.trace.instrumentation.kafka_clients.KafkaConsumerInstrumentation$ConsumeScopeAction"); +public final class KafkaConsumerInstrumentation extends Instrumenter.Default { + private static final String[] HELPER_CLASS_NAMES = + new String[] { + "datadog.trace.instrumentation.kafka_clients.TextMapExtractAdapter", + "datadog.trace.instrumentation.kafka_clients.TracingIterable", + "datadog.trace.instrumentation.kafka_clients.TracingIterable$TracingIterator", + "datadog.trace.instrumentation.kafka_clients.TracingIterable$SpanBuilderDecorator", + "datadog.trace.instrumentation.kafka_clients.KafkaConsumerInstrumentation$ConsumeScopeAction" + }; public KafkaConsumerInstrumentation() { super("kafka"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.kafka.clients.consumer.ConsumerRecords"), - classLoaderHasClasses( - "org.apache.kafka.common.header.Header", "org.apache.kafka.common.header.Headers")) - .transform(HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(named("records")) - .and(takesArgument(0, String.class)) - .and(returns(Iterable.class)), - IterableAdvice.class.getName()) - .advice( - isMethod() - .and(isPublic()) - .and(named("iterator")) - .and(takesArguments(0)) - .and(returns(Iterator.class)), - IteratorAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.kafka.clients.consumer.ConsumerRecords"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "org.apache.kafka.common.header.Header", "org.apache.kafka.common.header.Headers"); + } + + @Override + public String[] helperClassNames() { + return HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("records")) + .and(takesArgument(0, String.class)) + .and(returns(Iterable.class)), + IterableAdvice.class.getName()); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("iterator")) + .and(takesArguments(0)) + .and(returns(Iterator.class)), + IteratorAdvice.class.getName()); + return transformers; } public static class IterableAdvice { diff --git a/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaProducerInstrumentation.java b/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaProducerInstrumentation.java index 3d7bc68c1e..b31668ac69 100644 --- a/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaProducerInstrumentation.java +++ b/dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/KafkaProducerInstrumentation.java @@ -8,9 +8,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -20,18 +17,21 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.kafka.clients.producer.Callback; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.RecordMetadata; @AutoService(Instrumenter.class) -public final class KafkaProducerInstrumentation extends Instrumenter.Configurable { - public static final HelperInjector HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.kafka_clients.TextMapInjectAdapter", - KafkaProducerInstrumentation.class.getName() + "$ProducerCallback"); +public final class KafkaProducerInstrumentation extends Instrumenter.Default { + private static final String[] HELPER_CLASS_NAMES = + new String[] { + "datadog.trace.instrumentation.kafka_clients.TextMapInjectAdapter", + KafkaProducerInstrumentation.class.getName() + "$ProducerCallback" + }; private static final String OPERATION = "kafka.produce"; private static final String COMPONENT_NAME = "java-kafka"; @@ -41,26 +41,32 @@ public final class KafkaProducerInstrumentation extends Instrumenter.Configurabl } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.kafka.clients.producer.KafkaProducer"), - classLoaderHasClasses( - "org.apache.kafka.common.header.Header", "org.apache.kafka.common.header.Headers")) - .transform(HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(named("send")) - .and( - takesArgument( - 0, named("org.apache.kafka.clients.producer.ProducerRecord"))) - .and(takesArgument(1, named("org.apache.kafka.clients.producer.Callback"))), - ProducerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.kafka.clients.producer.KafkaProducer"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "org.apache.kafka.common.header.Header", "org.apache.kafka.common.header.Headers"); + } + + @Override + public String[] helperClassNames() { + return HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("send")) + .and(takesArgument(0, named("org.apache.kafka.clients.producer.ProducerRecord"))) + .and(takesArgument(1, named("org.apache.kafka.clients.producer.Callback"))), + ProducerAdvice.class.getName()); + return transformers; } public static class ProducerAdvice { diff --git a/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle b/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle index 103ce39df2..7f6ce7ac44 100644 --- a/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle +++ b/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle @@ -5,8 +5,7 @@ versionScan { module = "kafka-streams" versions = "[0.11.0.0,)" verifyPresent = [ - 'org.apache.kafka.streams.state.internals.CacheFunction' : null, - 'org.apache.kafka.streams.state.internals.InMemoryKeyValueStore': null, + 'org.apache.kafka.streams.state.internals.OrderedBytes' : null ] } diff --git a/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsProcessorInstrumentation.java b/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsProcessorInstrumentation.java index e9f8293bc8..85c42b548d 100644 --- a/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsProcessorInstrumentation.java +++ b/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsProcessorInstrumentation.java @@ -10,9 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -23,44 +20,51 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.kafka.streams.processor.internals.StampedRecord; public class KafkaStreamsProcessorInstrumentation { // These two instrumentations work together to apply StreamTask.process. // The combination of these are needed because there's not a good instrumentation point. - public static final HelperInjector HELPER_INJECTOR = - new HelperInjector("datadog.trace.instrumentation.kafka_streams.TextMapExtractAdapter"); + public static final String[] HELPER_CLASS_NAMES = + new String[] {"datadog.trace.instrumentation.kafka_streams.TextMapExtractAdapter"}; @AutoService(Instrumenter.class) - public static class StartInstrumentation extends Instrumenter.Configurable { + public static class StartInstrumentation extends Instrumenter.Default { public StartInstrumentation() { super("kafka", "kafka-streams"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.kafka.streams.processor.internals.PartitionGroup"), - classLoaderHasClasses("org.apache.kafka.streams.state.internals.KeyValueIterators")) - .transform(HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPackagePrivate()) - .and(named("nextRecord")) - .and( - returns( - named( - "org.apache.kafka.streams.processor.internals.StampedRecord"))), - StartSpanAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.kafka.streams.processor.internals.PartitionGroup"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.apache.kafka.streams.state.internals.OrderedBytes"); + } + + @Override + public String[] helperClassNames() { + return HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPackagePrivate()) + .and(named("nextRecord")) + .and(returns(named("org.apache.kafka.streams.processor.internals.StampedRecord"))), + StartSpanAdvice.class.getName()); + return transformers; } public static class StartSpanAdvice { @@ -92,28 +96,35 @@ public class KafkaStreamsProcessorInstrumentation { } @AutoService(Instrumenter.class) - public static class StopInstrumentation extends Instrumenter.Configurable { + public static class StopInstrumentation extends Instrumenter.Default { public StopInstrumentation() { super("kafka", "kafka-streams"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.kafka.streams.processor.internals.StreamTask"), - classLoaderHasClasses( - "org.apache.kafka.common.header.Header", - "org.apache.kafka.common.header.Headers")) - .transform(HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPublic()).and(named("process")).and(takesArguments(0)), - StopSpanAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.kafka.streams.processor.internals.StreamTask"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "org.apache.kafka.common.header.Header", "org.apache.kafka.common.header.Headers"); + } + + @Override + public String[] helperClassNames() { + return HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPublic()).and(named("process")).and(takesArguments(0)), + StopSpanAdvice.class.getName()); + return transformers; } public static class StopSpanAdvice { diff --git a/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsSourceNodeRecordDeserializerInstrumentation.java b/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsSourceNodeRecordDeserializerInstrumentation.java index 20449ceb7c..62cf2f1b5b 100644 --- a/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsSourceNodeRecordDeserializerInstrumentation.java +++ b/dd-java-agent/instrumentation/kafka-streams-0.11/src/main/java/datadog/trace/instrumentation/kafka_streams/KafkaStreamsSourceNodeRecordDeserializerInstrumentation.java @@ -8,42 +8,43 @@ import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.common.record.TimestampType; // This is necessary because SourceNodeRecordDeserializer drops the headers. :-( @AutoService(Instrumenter.class) -public class KafkaStreamsSourceNodeRecordDeserializerInstrumentation - extends Instrumenter.Configurable { +public class KafkaStreamsSourceNodeRecordDeserializerInstrumentation extends Instrumenter.Default { public KafkaStreamsSourceNodeRecordDeserializerInstrumentation() { super("kafka", "kafka-streams"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("org.apache.kafka.streams.processor.internals.SourceNodeRecordDeserializer"), - classLoaderHasClasses("org.apache.kafka.streams.state.internals.KeyValueIterators")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(named("deserialize")) - .and( - takesArgument( - 0, named("org.apache.kafka.clients.consumer.ConsumerRecord"))) - .and(returns(named("org.apache.kafka.clients.consumer.ConsumerRecord"))), - SaveHeadersAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("org.apache.kafka.streams.processor.internals.SourceNodeRecordDeserializer"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("org.apache.kafka.streams.state.internals.OrderedBytes"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(named("deserialize")) + .and(takesArgument(0, named("org.apache.kafka.clients.consumer.ConsumerRecord"))) + .and(returns(named("org.apache.kafka.clients.consumer.ConsumerRecord"))), + SaveHeadersAdvice.class.getName()); + return transformers; } public static class SaveHeadersAdvice { diff --git a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceAsyncCommandsInstrumentation.java b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceAsyncCommandsInstrumentation.java index beda0d95fd..32fbce4a1d 100644 --- a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceAsyncCommandsInstrumentation.java +++ b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceAsyncCommandsInstrumentation.java @@ -4,21 +4,13 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClass import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class LettuceAsyncCommandsInstrumentation extends Instrumenter.Configurable { - - private static final HelperInjector REDIS_ASYNC_HELPERS = - new HelperInjector( - LettuceAsyncCommandsInstrumentation.class.getPackage().getName() - + ".LettuceAsyncBiFunction", - LettuceAsyncCommandsInstrumentation.class.getPackage().getName() - + ".LettuceInstrumentationUtil"); +public class LettuceAsyncCommandsInstrumentation extends Instrumenter.Default { public LettuceAsyncCommandsInstrumentation() { super("lettuce", "lettuce-5-async"); @@ -30,20 +22,32 @@ public class LettuceAsyncCommandsInstrumentation extends Instrumenter.Configurab } @Override - protected AgentBuilder apply(AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("io.lettuce.core.AbstractRedisAsyncCommands"), - classLoaderHasClasses("io.lettuce.core.RedisClient")) - .transform(REDIS_ASYNC_HELPERS) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(named("dispatch")) - .and(takesArgument(0, named("io.lettuce.core.protocol.RedisCommand"))), - LettuceAsyncCommandsAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("io.lettuce.core.AbstractRedisAsyncCommands"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("io.lettuce.core.RedisClient"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + LettuceAsyncCommandsInstrumentation.class.getPackage().getName() + ".LettuceAsyncBiFunction", + LettuceAsyncCommandsInstrumentation.class.getPackage().getName() + + ".LettuceInstrumentationUtil" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("dispatch")) + .and(takesArgument(0, named("io.lettuce.core.protocol.RedisCommand"))), + LettuceAsyncCommandsAdvice.class.getName()); + return transformers; } } diff --git a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceClientInstrumentation.java b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceClientInstrumentation.java index a21e773e07..31229ec255 100644 --- a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceClientInstrumentation.java +++ b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceClientInstrumentation.java @@ -4,20 +4,20 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClass import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class LettuceClientInstrumentation extends Instrumenter.Configurable { +public final class LettuceClientInstrumentation extends Instrumenter.Default { - private static final HelperInjector REDIS_ASYNC_HELPERS = - new HelperInjector( - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".LettuceInstrumentationUtil", - LettuceClientInstrumentation.class.getPackage().getName() + ".LettuceAsyncBiFunction"); + private static final String[] HELPER_CLASS_NAMES = + new String[] { + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".LettuceInstrumentationUtil", + LettuceClientInstrumentation.class.getPackage().getName() + ".LettuceAsyncBiFunction" + }; public LettuceClientInstrumentation() { super("lettuce"); @@ -29,23 +29,31 @@ public final class LettuceClientInstrumentation extends Instrumenter.Configurabl } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("io.lettuce.core.RedisClient"), - classLoaderHasClasses("io.lettuce.core.RedisClient")) - .transform(DDTransformers.defaultTransformers()) - .transform(REDIS_ASYNC_HELPERS) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPrivate()) - .and(returns(named("io.lettuce.core.ConnectionFuture"))) - .and(nameStartsWith("connect")) - .and(nameEndsWith("Async")) - .and(takesArgument(1, named("io.lettuce.core.RedisURI"))), - ConnectionFutureAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("io.lettuce.core.RedisClient"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("io.lettuce.core.RedisClient"); + } + + @Override + public String[] helperClassNames() { + return HELPER_CLASS_NAMES; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPrivate()) + .and(returns(named("io.lettuce.core.ConnectionFuture"))) + .and(nameStartsWith("connect")) + .and(nameEndsWith("Async")) + .and(takesArgument(1, named("io.lettuce.core.RedisURI"))), + ConnectionFutureAdvice.class.getName()); + return transformers; } } diff --git a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceReactiveCommandsInstrumentation.java b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceReactiveCommandsInstrumentation.java index 7a42f4ec81..700b031450 100644 --- a/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceReactiveCommandsInstrumentation.java +++ b/dd-java-agent/instrumentation/lettuce-5/src/main/java/datadog/trace/instrumentation/lettuce/LettuceReactiveCommandsInstrumentation.java @@ -4,31 +4,15 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClass import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.instrumentation.lettuce.rx.LettuceFluxCreationAdvice; import datadog.trace.instrumentation.lettuce.rx.LettuceMonoCreationAdvice; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class LettuceReactiveCommandsInstrumentation extends Instrumenter.Configurable { - - private static final HelperInjector REDIS_RX_HELPERS = - new HelperInjector( - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".LettuceInstrumentationUtil", - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".rx.LettuceMonoCreationAdvice", - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".rx.LettuceMonoDualConsumer", - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".rx.LettuceFluxCreationAdvice", - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".rx.LettuceFluxTerminationRunnable", - LettuceReactiveCommandsInstrumentation.class.getPackage().getName() - + ".rx.LettuceFluxTerminationRunnable$FluxOnSubscribeConsumer"); +public class LettuceReactiveCommandsInstrumentation extends Instrumenter.Default { public LettuceReactiveCommandsInstrumentation() { super("lettuce", "lettuce-5-rx"); @@ -40,28 +24,50 @@ public class LettuceReactiveCommandsInstrumentation extends Instrumenter.Configu } @Override - protected AgentBuilder apply(AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("io.lettuce.core.AbstractRedisReactiveCommands"), - classLoaderHasClasses("io.lettuce.core.RedisClient")) - .transform(REDIS_RX_HELPERS) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(named("createMono")) - .and(takesArgument(0, named("java.util.function.Supplier"))) - .and(returns(named("reactor.core.publisher.Mono"))), - LettuceMonoCreationAdvice.class.getName()) - .advice( - isMethod() - .and(nameStartsWith("create")) - .and(nameEndsWith("Flux")) - .and(takesArgument(0, named("java.util.function.Supplier"))) - .and(returns(named(("reactor.core.publisher.Flux")))), - LettuceFluxCreationAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("io.lettuce.core.AbstractRedisReactiveCommands"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("io.lettuce.core.RedisClient"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".LettuceInstrumentationUtil", + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".rx.LettuceMonoCreationAdvice", + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".rx.LettuceMonoDualConsumer", + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".rx.LettuceFluxCreationAdvice", + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".rx.LettuceFluxTerminationRunnable", + LettuceReactiveCommandsInstrumentation.class.getPackage().getName() + + ".rx.LettuceFluxTerminationRunnable$FluxOnSubscribeConsumer" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("createMono")) + .and(takesArgument(0, named("java.util.function.Supplier"))) + .and(returns(named("reactor.core.publisher.Mono"))), + LettuceMonoCreationAdvice.class.getName()); + transformers.put( + isMethod() + .and(nameStartsWith("create")) + .and(nameEndsWith("Flux")) + .and(takesArgument(0, named("java.util.function.Supplier"))) + .and(returns(named(("reactor.core.publisher.Flux")))), + LettuceFluxCreationAdvice.class.getName()); + + return transformers; } } diff --git a/dd-java-agent/instrumentation/mongo-3.1/src/main/java/datadog/trace/instrumentation/mongo/MongoClientInstrumentation.java b/dd-java-agent/instrumentation/mongo-3.1/src/main/java/datadog/trace/instrumentation/mongo/MongoClientInstrumentation.java index 9568b7aaa7..ab8777edd1 100644 --- a/dd-java-agent/instrumentation/mongo-3.1/src/main/java/datadog/trace/instrumentation/mongo/MongoClientInstrumentation.java +++ b/dd-java-agent/instrumentation/mongo-3.1/src/main/java/datadog/trace/instrumentation/mongo/MongoClientInstrumentation.java @@ -8,50 +8,53 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; import com.mongodb.MongoClientOptions; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Modifier; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class MongoClientInstrumentation extends Instrumenter.Configurable { - public static final HelperInjector MONGO_HELPER_INJECTOR = - new HelperInjector("datadog.trace.instrumentation.mongo.DDTracingCommandListener"); +public final class MongoClientInstrumentation extends Instrumenter.Default { + public static final String[] HELPERS = + new String[] {"datadog.trace.instrumentation.mongo.DDTracingCommandListener"}; public MongoClientInstrumentation() { super("mongo"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("com.mongodb.MongoClientOptions$Builder") - .and( - declaresMethod( - named("addCommandListener") - .and( - takesArguments( - new TypeDescription.Latent( - "com.mongodb.event.CommandListener", - Modifier.PUBLIC, - null, - Collections.emptyList()))) - .and(isPublic())))) - .transform(MONGO_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), - MongoClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("com.mongodb.MongoClientOptions$Builder") + .and( + declaresMethod( + named("addCommandListener") + .and( + takesArguments( + new TypeDescription.Latent( + "com.mongodb.event.CommandListener", + Modifier.PUBLIC, + null, + Collections.emptyList()))) + .and(isPublic()))); + } + + @Override + public String[] helperClassNames() { + return HELPERS; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), + MongoClientAdvice.class.getName()); + return transformers; } public static class MongoClientAdvice { diff --git a/dd-java-agent/instrumentation/mongo-async-3.3/src/main/java/datadog/trace/instrumentation/mongo/MongoAsyncClientInstrumentation.java b/dd-java-agent/instrumentation/mongo-async-3.3/src/main/java/datadog/trace/instrumentation/mongo/MongoAsyncClientInstrumentation.java index e9b6b247e0..0d75bea8c2 100644 --- a/dd-java-agent/instrumentation/mongo-async-3.3/src/main/java/datadog/trace/instrumentation/mongo/MongoAsyncClientInstrumentation.java +++ b/dd-java-agent/instrumentation/mongo-async-3.3/src/main/java/datadog/trace/instrumentation/mongo/MongoAsyncClientInstrumentation.java @@ -8,47 +8,51 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; import com.mongodb.async.client.MongoClientSettings; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Modifier; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class MongoAsyncClientInstrumentation extends Instrumenter.Configurable { +public final class MongoAsyncClientInstrumentation extends Instrumenter.Default { public MongoAsyncClientInstrumentation() { super("mongo"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("com.mongodb.async.client.MongoClientSettings$Builder") - .and( - declaresMethod( - named("addCommandListener") - .and( - takesArguments( - new TypeDescription.Latent( - "com.mongodb.event.CommandListener", - Modifier.PUBLIC, - null, - Collections.emptyList()))) - .and(isPublic())))) - .transform(MongoClientInstrumentation.MONGO_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), - MongoAsyncClientAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("com.mongodb.async.client.MongoClientSettings$Builder") + .and( + declaresMethod( + named("addCommandListener") + .and( + takesArguments( + new TypeDescription.Latent( + "com.mongodb.event.CommandListener", + Modifier.PUBLIC, + null, + Collections.emptyList()))) + .and(isPublic()))); + } + + @Override + public String[] helperClassNames() { + return MongoClientInstrumentation.HELPERS; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), + MongoAsyncClientAdvice.class.getName()); + return transformers; } public static class MongoAsyncClientAdvice { diff --git a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java index 07886b6212..0023a432d5 100644 --- a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java @@ -10,9 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.instrumentation.netty40.client.HttpClientRequestTracingHandler; @@ -29,11 +26,13 @@ import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpServerCodec; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class NettyChannelPipelineInstrumentation extends Instrumenter.Configurable { +public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { private static final String PACKAGE = NettyChannelPipelineInstrumentation.class.getPackage().getName(); @@ -48,32 +47,40 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Configurab } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(hasSuperType(named("io.netty.channel.ChannelPipeline"))), - classLoaderHasClasses("io.netty.channel.local.LocalEventLoop")) - .transform( - new HelperInjector( - // client helpers - PACKAGE + ".client.NettyResponseInjectAdapter", - PACKAGE + ".client.HttpClientRequestTracingHandler", - PACKAGE + ".client.HttpClientResponseTracingHandler", - PACKAGE + ".client.HttpClientTracingHandler", - // server helpers - PACKAGE + ".server.NettyRequestExtractAdapter", - PACKAGE + ".server.HttpServerRequestTracingHandler", - PACKAGE + ".server.HttpServerResponseTracingHandler", - PACKAGE + ".server.HttpServerTracingHandler")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(nameStartsWith("add")) - .and(takesArgument(2, named("io.netty.channel.ChannelHandler"))), - ChannelPipelineAddAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("io.netty.channel.ChannelPipeline"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("io.netty.channel.local.LocalEventLoop"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + // client helpers + PACKAGE + ".client.NettyResponseInjectAdapter", + PACKAGE + ".client.HttpClientRequestTracingHandler", + PACKAGE + ".client.HttpClientResponseTracingHandler", + PACKAGE + ".client.HttpClientTracingHandler", + // server helpers + PACKAGE + ".server.NettyRequestExtractAdapter", + PACKAGE + ".server.HttpServerRequestTracingHandler", + PACKAGE + ".server.HttpServerResponseTracingHandler", + PACKAGE + ".server.HttpServerTracingHandler" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(nameStartsWith("add")) + .and(takesArgument(2, named("io.netty.channel.ChannelHandler"))), + ChannelPipelineAddAdvice.class.getName()); + return transformers; } /** diff --git a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java index bb3dfdacb6..311f10b60a 100644 --- a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java @@ -10,9 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.instrumentation.netty41.client.HttpClientRequestTracingHandler; @@ -29,11 +26,13 @@ import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpServerCodec; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class NettyChannelPipelineInstrumentation extends Instrumenter.Configurable { +public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { private static final String PACKAGE = NettyChannelPipelineInstrumentation.class.getPackage().getName(); @@ -48,32 +47,40 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Configurab } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(hasSuperType(named("io.netty.channel.ChannelPipeline"))), - classLoaderHasClasses("io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder")) - .transform( - new HelperInjector( - // client helpers - PACKAGE + ".client.NettyResponseInjectAdapter", - PACKAGE + ".client.HttpClientRequestTracingHandler", - PACKAGE + ".client.HttpClientResponseTracingHandler", - PACKAGE + ".client.HttpClientTracingHandler", - // server helpers - PACKAGE + ".server.NettyRequestExtractAdapter", - PACKAGE + ".server.HttpServerRequestTracingHandler", - PACKAGE + ".server.HttpServerResponseTracingHandler", - PACKAGE + ".server.HttpServerTracingHandler")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(nameStartsWith("add")) - .and(takesArgument(2, named("io.netty.channel.ChannelHandler"))), - ChannelPipelineAddAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("io.netty.channel.ChannelPipeline"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + // client helpers + PACKAGE + ".client.NettyResponseInjectAdapter", + PACKAGE + ".client.HttpClientRequestTracingHandler", + PACKAGE + ".client.HttpClientResponseTracingHandler", + PACKAGE + ".client.HttpClientTracingHandler", + // server helpers + PACKAGE + ".server.NettyRequestExtractAdapter", + PACKAGE + ".server.HttpServerRequestTracingHandler", + PACKAGE + ".server.HttpServerResponseTracingHandler", + PACKAGE + ".server.HttpServerTracingHandler" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(nameStartsWith("add")) + .and(takesArgument(2, named("io.netty.channel.ChannelHandler"))), + ChannelPipelineAddAdvice.class.getName()); + return transformers; } /** diff --git a/dd-java-agent/instrumentation/okhttp-3/src/main/java/datadog/trace/instrumentation/okhttp3/OkHttp3Instrumentation.java b/dd-java-agent/instrumentation/okhttp-3/src/main/java/datadog/trace/instrumentation/okhttp3/OkHttp3Instrumentation.java index 70f70990ff..229203f44e 100644 --- a/dd-java-agent/instrumentation/okhttp-3/src/main/java/datadog/trace/instrumentation/okhttp3/OkHttp3Instrumentation.java +++ b/dd-java-agent/instrumentation/okhttp-3/src/main/java/datadog/trace/instrumentation/okhttp3/OkHttp3Instrumentation.java @@ -7,57 +7,64 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import io.opentracing.util.GlobalTracer; import java.util.Collections; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import okhttp3.Interceptor; import okhttp3.OkHttpClient; @AutoService(Instrumenter.class) -public class OkHttp3Instrumentation extends Instrumenter.Configurable { +public class OkHttp3Instrumentation extends Instrumenter.Default { public OkHttp3Instrumentation() { super("okhttp", "okhttp-3"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named("okhttp3.OkHttpClient"), - classLoaderHasClasses( - "okhttp3.Request", - "okhttp3.Response", - "okhttp3.Connection", - "okhttp3.Cookie", - "okhttp3.ConnectionPool", - "okhttp3.Headers")) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.okhttp3.OkHttpClientSpanDecorator", - "datadog.trace.instrumentation.okhttp3.OkHttpClientSpanDecorator$1", - "datadog.trace.instrumentation.okhttp3.RequestBuilderInjectAdapter", - "datadog.trace.instrumentation.okhttp3.TagWrapper", - "datadog.trace.instrumentation.okhttp3.TracedCallable", - "datadog.trace.instrumentation.okhttp3.TracedExecutor", - "datadog.trace.instrumentation.okhttp3.TracedExecutorService", - "datadog.trace.instrumentation.okhttp3.TracedRunnable", - "datadog.trace.instrumentation.okhttp3.TracingInterceptor", - "datadog.trace.instrumentation.okhttp3.TracingCallFactory", - "datadog.trace.instrumentation.okhttp3.TracingCallFactory$NetworkInterceptor", - "datadog.trace.instrumentation.okhttp3.TracingCallFactory$1")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isConstructor().and(takesArgument(0, named("okhttp3.OkHttpClient$Builder"))), - OkHttp3Advice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("okhttp3.OkHttpClient"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "okhttp3.Request", + "okhttp3.Response", + "okhttp3.Connection", + "okhttp3.Cookie", + "okhttp3.ConnectionPool", + "okhttp3.Headers"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.okhttp3.OkHttpClientSpanDecorator", + "datadog.trace.instrumentation.okhttp3.OkHttpClientSpanDecorator$1", + "datadog.trace.instrumentation.okhttp3.RequestBuilderInjectAdapter", + "datadog.trace.instrumentation.okhttp3.TagWrapper", + "datadog.trace.instrumentation.okhttp3.TracedCallable", + "datadog.trace.instrumentation.okhttp3.TracedExecutor", + "datadog.trace.instrumentation.okhttp3.TracedExecutorService", + "datadog.trace.instrumentation.okhttp3.TracedRunnable", + "datadog.trace.instrumentation.okhttp3.TracingInterceptor", + "datadog.trace.instrumentation.okhttp3.TracingCallFactory", + "datadog.trace.instrumentation.okhttp3.TracingCallFactory$NetworkInterceptor", + "datadog.trace.instrumentation.okhttp3.TracingCallFactory$1" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isConstructor().and(takesArgument(0, named("okhttp3.OkHttpClient$Builder"))), + OkHttp3Advice.class.getName()); + return transformers; } public static class OkHttp3Advice { diff --git a/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java b/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java index 702a4dc304..af2339cd19 100644 --- a/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java +++ b/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java @@ -1,58 +1,55 @@ package datadog.trace.instrumentation.osgi; -import static net.bytebuddy.matcher.ElementMatchers.named; - import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Utils; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.utility.JavaModule; +import java.util.Collections; +import java.util.Map; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.NameMatcher; +import net.bytebuddy.matcher.StringMatcher; @AutoService(Instrumenter.class) -public final class OSGIClassloadingInstrumentation extends Instrumenter.Configurable { +public final class OSGIClassloadingInstrumentation extends Instrumenter.Default { public OSGIClassloadingInstrumentation() { super("osgi-classloading"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - // OSGI Bundle class loads the sys prop which defines bootstrap classes - .type(named("org.osgi.framework.Bundle")) - .transform(DDTransformers.defaultTransformers()) - .transform( - new AgentBuilder.Transformer() { - @Override - public DynamicType.Builder transform( - DynamicType.Builder builder, - TypeDescription typeDescription, - ClassLoader classLoader, - JavaModule javaModule) { - // This instrumentation modifies no bytes. - // Instead it sets a system prop to tell osgi to delegate - // classloads for datadog bootstrap classes - StringBuilder ddPrefixes = new StringBuilder(""); - for (int i = 0; i < Utils.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { - if (i > 0) { - // must append twice. Once for exact package and wildcard for child packages - ddPrefixes.append(","); - } - ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]).append(".*,"); - ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]); + public ElementMatcher typeMatcher() { + // OSGI Bundle class loads the sys prop which defines bootstrap classes + return new NameMatcher( + new StringMatcher("org.osgi.framework.Bundle", StringMatcher.Mode.EQUALS_FULLY) { + @Override + public boolean matches(String target) { + if (super.matches(target)) { + // This instrumentation modifies no bytes. + // Instead it sets a system prop to tell osgi to delegate + // classloads for datadog bootstrap classes + StringBuilder ddPrefixes = new StringBuilder(""); + for (int i = 0; i < Utils.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { + if (i > 0) { + // must append twice. Once for exact package and wildcard for child packages + ddPrefixes.append(","); } - final String existing = System.getProperty("org.osgi.framework.bootdelegation"); - if (null == existing) { - System.setProperty("org.osgi.framework.bootdelegation", ddPrefixes.toString()); - } else if (!existing.contains(ddPrefixes)) { - System.setProperty( - "org.osgi.framework.bootdelegation", existing + "," + ddPrefixes.toString()); - } - return builder; + ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]).append(".*,"); + ddPrefixes.append(Utils.BOOTSTRAP_PACKAGE_PREFIXES[i]); } - }) - .asDecorator(); + final String existing = System.getProperty("org.osgi.framework.bootdelegation"); + if (null == existing) { + System.setProperty("org.osgi.framework.bootdelegation", ddPrefixes.toString()); + } else if (!existing.contains(ddPrefixes)) { + System.setProperty( + "org.osgi.framework.bootdelegation", existing + "," + ddPrefixes.toString()); + } + } + return false; + } + }); + } + + @Override + public Map transformers() { + return Collections.emptyMap(); } } diff --git a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java index 04b858bfe3..e63a89063f 100644 --- a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java +++ b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java @@ -19,8 +19,8 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.*; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.slf4j.LoggerFactory; import play.api.mvc.Action; import play.api.mvc.Request; @@ -31,43 +31,47 @@ import scala.concurrent.Future; @Slf4j @AutoService(Instrumenter.class) -public final class PlayInstrumentation extends Instrumenter.Configurable { - private static final HelperInjector PLAY_HELPERS = - new HelperInjector( - PlayInstrumentation.class.getName() + "$RequestCallback", - PlayInstrumentation.class.getName() + "$RequestError", - PlayInstrumentation.class.getName() + "$PlayHeaders"); +public final class PlayInstrumentation extends Instrumenter.Default { public PlayInstrumentation() { super("play"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - hasSuperType(named("play.api.mvc.Action")), - classLoaderHasClasses( - "akka.japi.JavaPartialFunction", - "play.api.mvc.Action", - "play.api.mvc.Result", - "scala.Option", - "scala.Tuple2", - "scala.concurrent.Future") - .and(classLoaderHasClassWithMethod("play.api.mvc.Request", "tags"))) - .and( - declaresMethod( - named("executionContext").and(returns(named("scala.concurrent.ExecutionContext"))))) - .transform(PLAY_HELPERS) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("apply") - .and(takesArgument(0, named("play.api.mvc.Request"))) - .and(returns(named("scala.concurrent.Future"))), - PlayAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return hasSuperType(named("play.api.mvc.Action")); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses( + "akka.japi.JavaPartialFunction", + "play.api.mvc.Action", + "play.api.mvc.Result", + "scala.Option", + "scala.Tuple2", + "scala.concurrent.Future") + .and(classLoaderHasClassWithMethod("play.api.mvc.Request", "tags")); + } + + @Override + public String[] helperClassNames() { + return new String[] { + PlayInstrumentation.class.getName() + "$RequestCallback", + PlayInstrumentation.class.getName() + "$RequestError", + PlayInstrumentation.class.getName() + "$PlayHeaders" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("apply") + .and(takesArgument(0, named("play.api.mvc.Request"))) + .and(returns(named("scala.concurrent.Future"))), + PlayAdvice.class.getName()); + return transformers; } public static class PlayAdvice { diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackHttpClientInstrumentation.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackHttpClientInstrumentation.java index 10a1b943ac..5a022dde4c 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackHttpClientInstrumentation.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackHttpClientInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.ratpack; -import static datadog.trace.instrumentation.ratpack.RatpackInstrumentation.ROOT_RATPACK_HELPER_INJECTOR; +import static datadog.trace.instrumentation.ratpack.RatpackInstrumentation.CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE; import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -8,27 +8,17 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice; import java.net.URI; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class RatpackHttpClientInstrumentation extends Instrumenter.Configurable { +public final class RatpackHttpClientInstrumentation extends Instrumenter.Default { - private static final HelperInjector HTTP_CLIENT_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestAdvice", - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestStreamAdvice", - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpGetAdvice", - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RequestAction", - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$ResponseAction", - "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$StreamedResponseAction", - "datadog.trace.instrumentation.ratpack.impl.RequestSpecInjectAdapter", - "datadog.trace.instrumentation.ratpack.impl.WrappedRequestSpec"); public static final TypeDescription.ForLoadedType URI_TYPE_DESCRIPTION = new TypeDescription.ForLoadedType(URI.class); @@ -38,45 +28,59 @@ public final class RatpackHttpClientInstrumentation extends Instrumenter.Configu @Override protected boolean defaultEnabled() { + // FIXME: Injecting ContextualScopeManager is probably a bug. Verify and check all ratpack helpers before enabling. return false; } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("ratpack.http.client.HttpClient"))); + } - return agentBuilder - .type( - not(isInterface()).and(hasSuperType(named("ratpack.http.client.HttpClient"))), - RatpackInstrumentation.CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE) - .transform(ROOT_RATPACK_HELPER_INJECTOR) - .transform(HTTP_CLIENT_HELPER_INJECTOR) - .transform( - DDAdvice.create() - .advice( - named("request") - .and( - takesArguments( - URI_TYPE_DESCRIPTION, - RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), - RatpackHttpClientAdvice.RatpackHttpClientRequestAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - named("requestStream") - .and( - takesArguments( - URI_TYPE_DESCRIPTION, - RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), - RatpackHttpClientAdvice.RatpackHttpClientRequestStreamAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - named("get") - .and( - takesArguments( - URI_TYPE_DESCRIPTION, - RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), - RatpackHttpClientAdvice.RatpackHttpGetAdvice.class.getName())) - .asDecorator(); + @Override + public ElementMatcher classLoaderMatcher() { + return CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE; + } + + @Override + public String[] helperClassNames() { + return new String[] { + // http helpers + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestAdvice", + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestStreamAdvice", + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpGetAdvice", + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RequestAction", + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$ResponseAction", + "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$StreamedResponseAction", + "datadog.trace.instrumentation.ratpack.impl.RequestSpecInjectAdapter", + "datadog.trace.instrumentation.ratpack.impl.WrappedRequestSpec", + // core helpers + "datadog.opentracing.scopemanager.ContextualScopeManager", + "datadog.opentracing.scopemanager.ScopeContext" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("request") + .and( + takesArguments( + URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), + RatpackHttpClientAdvice.RatpackHttpClientRequestAdvice.class.getName()); + transformers.put( + named("requestStream") + .and( + takesArguments( + URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), + RatpackHttpClientAdvice.RatpackHttpClientRequestStreamAdvice.class.getName()); + transformers.put( + named("get") + .and( + takesArguments( + URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)), + RatpackHttpClientAdvice.RatpackHttpGetAdvice.class.getName()); + return transformers; } } diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java index 164258e12d..1502300456 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java @@ -4,38 +4,21 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClass import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice; import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) @Slf4j -public final class RatpackInstrumentation extends Instrumenter.Configurable { +public final class RatpackInstrumentation extends Instrumenter.Default { static final String EXEC_NAME = "ratpack"; - static final HelperInjector ROOT_RATPACK_HELPER_INJECTOR = - new HelperInjector( - "datadog.opentracing.scopemanager.ContextualScopeManager", - "datadog.opentracing.scopemanager.ScopeContext"); - - private static final HelperInjector SERVER_REGISTRY_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter", - "datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager", - "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice", - "datadog.trace.instrumentation.ratpack.impl.TracingHandler"); - private static final HelperInjector EXEC_STARTER_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice", - "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction"); - static final TypeDescription.Latent ACTION_TYPE_DESCRIPTION = new TypeDescription.Latent("ratpack.func.Action", Modifier.PUBLIC, null); @@ -53,41 +36,121 @@ public final class RatpackInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { + public ElementMatcher typeMatcher() { + return named("ratpack.server.internal.ServerRegistry"); + } - return agentBuilder - .type( - named("ratpack.server.internal.ServerRegistry"), - CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE) - .transform(ROOT_RATPACK_HELPER_INJECTOR) - .transform(SERVER_REGISTRY_HELPER_INJECTOR) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isStatic()).and(named("buildBaseRegistry")), - RatpackServerAdvice.RatpackServerRegistryAdvice.class.getName())) - .asDecorator() - .type( - not(isInterface()).and(hasSuperType(named("ratpack.exec.ExecStarter"))), - CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE) - .transform(ROOT_RATPACK_HELPER_INJECTOR) - .transform(EXEC_STARTER_HELPER_INJECTOR) - .transform( - DDAdvice.create() - .advice( - named("register").and(takesArguments(ACTION_TYPE_DESCRIPTION)), - RatpackServerAdvice.ExecStarterAdvice.class.getName())) - .asDecorator() - .type( - named("ratpack.exec.Execution") - .or(not(isInterface()).and(hasSuperType(named("ratpack.exec.Execution")))), - CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE) - .transform(EXEC_STARTER_HELPER_INJECTOR) - .transform( - DDAdvice.create() - .advice( - named("fork").and(returns(named("ratpack.exec.ExecStarter"))), - RatpackServerAdvice.ExecutionAdvice.class.getName())) - .asDecorator(); + @Override + public ElementMatcher classLoaderMatcher() { + return CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE; + } + + @Override + public String[] helperClassNames() { + return new String[] { + // core helpers + "datadog.opentracing.scopemanager.ContextualScopeManager", + "datadog.opentracing.scopemanager.ScopeContext", + // service registry helpers + "datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter", + "datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager", + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice", + "datadog.trace.instrumentation.ratpack.impl.TracingHandler" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod().and(isStatic()).and(named("buildBaseRegistry")), + RatpackServerAdvice.RatpackServerRegistryAdvice.class.getName()); + return transformers; + } + + @AutoService(Instrumenter.class) + public static class ExecStarterInstrumentation extends Instrumenter.Default { + + public ExecStarterInstrumentation() { + super(EXEC_NAME); + } + + @Override + protected boolean defaultEnabled() { + return false; + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(hasSuperType(named("ratpack.exec.ExecStarter"))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE; + } + + @Override + public String[] helperClassNames() { + return new String[] { + // core helpers + "datadog.opentracing.scopemanager.ContextualScopeManager", + "datadog.opentracing.scopemanager.ScopeContext", + // exec helpers + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice", + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("register").and(takesArguments(ACTION_TYPE_DESCRIPTION)), + RatpackServerAdvice.ExecStarterAdvice.class.getName()); + return transformers; + } + } + + @AutoService(Instrumenter.class) + public static class ExecutionInstrumentation extends Default { + + public ExecutionInstrumentation() { + super(EXEC_NAME); + } + + @Override + protected boolean defaultEnabled() { + return false; + } + + @Override + public ElementMatcher typeMatcher() { + return named("ratpack.exec.Execution") + .or(not(isInterface()).and(hasSuperType(named("ratpack.exec.Execution")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return CLASSLOADER_CONTAINS_RATPACK_1_4_OR_ABOVE; + } + + @Override + public String[] helperClassNames() { + return new String[] { + // exec helpers + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice", + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("fork").and(returns(named("ratpack.exec.ExecStarter"))), + RatpackServerAdvice.ExecutionAdvice.class.getName()); + return transformers; + } } } diff --git a/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/FilterChain2Instrumentation.java b/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/FilterChain2Instrumentation.java index b28d895faa..bd4f760536 100644 --- a/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/FilterChain2Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/FilterChain2Instrumentation.java @@ -11,8 +11,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,15 +22,17 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class FilterChain2Instrumentation extends Instrumenter.Configurable { +public final class FilterChain2Instrumentation extends Instrumenter.Default { public static final String FILTER_CHAIN_OPERATION_NAME = "servlet.request"; public FilterChain2Instrumentation() { @@ -40,25 +40,33 @@ public final class FilterChain2Instrumentation extends Instrumenter.Configurable } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.FilterChain")))), - not(classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")) - .and( - classLoaderHasClasses( - "javax.servlet.ServletContextEvent", "javax.servlet.ServletRequest"))) - .transform(HttpServlet2Instrumentation.SERVLET2_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("doFilter") - .and(takesArgument(0, named("javax.servlet.ServletRequest"))) - .and(takesArgument(1, named("javax.servlet.ServletResponse"))) - .and(isPublic()), - FilterChain2Advice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.FilterChain")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")) + .and( + classLoaderHasClasses( + "javax.servlet.ServletContextEvent", "javax.servlet.ServletRequest")); + } + + @Override + public String[] helperClassNames() { + return HttpServlet2Instrumentation.HELPERS; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("doFilter") + .and(takesArgument(0, named("javax.servlet.ServletRequest"))) + .and(takesArgument(1, named("javax.servlet.ServletResponse"))) + .and(isPublic()), + FilterChain2Advice.class.getName()); + return transformers; } public static class FilterChain2Advice { diff --git a/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/HttpServlet2Instrumentation.java b/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/HttpServlet2Instrumentation.java index fc65a7bdf5..1bffbd412a 100644 --- a/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/HttpServlet2Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet-2/src/main/java/datadog/trace/instrumentation/servlet2/HttpServlet2Instrumentation.java @@ -11,9 +11,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -25,45 +22,56 @@ import io.opentracing.propagation.Format; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class HttpServlet2Instrumentation extends Instrumenter.Configurable { +public final class HttpServlet2Instrumentation extends Instrumenter.Default { public static final String SERVLET_OPERATION_NAME = "servlet.request"; - static final HelperInjector SERVLET2_HELPER_INJECTOR = - new HelperInjector( - "datadog.trace.instrumentation.servlet2.HttpServletRequestExtractAdapter", - "datadog.trace.instrumentation.servlet2.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator"); + static final String[] HELPERS = + new String[] { + "datadog.trace.instrumentation.servlet2.HttpServletRequestExtractAdapter", + "datadog.trace.instrumentation.servlet2.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator" + }; public HttpServlet2Instrumentation() { super("servlet", "servlet-2"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.http.HttpServlet")))), - not(classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")) - .and( - classLoaderHasClasses( - "javax.servlet.ServletContextEvent", "javax.servlet.FilterChain"))) - .transform(SERVLET2_HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create(false) // Can't use the error handler for pre 1.5 classes... - .advice( - named("service") - .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) - .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) - .and(isProtected()), - HttpServlet2Advice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.http.HttpServlet")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")) + .and( + classLoaderHasClasses( + "javax.servlet.ServletContextEvent", "javax.servlet.FilterChain")); + } + + @Override + public String[] helperClassNames() { + return HELPERS; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("service") + .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) + .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) + .and(isProtected()), + HttpServlet2Advice.class.getName()); + return transformers; } public static class HttpServlet2Advice { diff --git a/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java b/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java index 3b52294ff0..60974a3b1f 100644 --- a/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/FilterChain3Instrumentation.java @@ -11,9 +11,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -26,6 +23,8 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -33,11 +32,11 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class FilterChain3Instrumentation extends Instrumenter.Configurable { +public final class FilterChain3Instrumentation extends Instrumenter.Default { public static final String SERVLET_OPERATION_NAME = "servlet.request"; public FilterChain3Instrumentation() { @@ -45,26 +44,34 @@ public final class FilterChain3Instrumentation extends Instrumenter.Configurable } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.FilterChain")))), - classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter", - "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", - FilterChain3Advice.class.getName() + "$TagSettingAsyncListener")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("doFilter") - .and(takesArgument(0, named("javax.servlet.ServletRequest"))) - .and(takesArgument(1, named("javax.servlet.ServletResponse"))) - .and(isPublic()), - FilterChain3Advice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.FilterChain")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter", + "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", + FilterChain3Advice.class.getName() + "$TagSettingAsyncListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("doFilter") + .and(takesArgument(0, named("javax.servlet.ServletRequest"))) + .and(takesArgument(1, named("javax.servlet.ServletResponse"))) + .and(isPublic()), + FilterChain3Advice.class.getName()); + return transformers; } public static class FilterChain3Advice { diff --git a/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java b/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java index 841931afb1..b64f7d34e9 100644 --- a/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet-3/src/main/java/datadog/trace/instrumentation/servlet3/HttpServlet3Instrumentation.java @@ -10,9 +10,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; -import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -25,43 +22,50 @@ import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.io.IOException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public final class HttpServlet3Instrumentation extends Instrumenter.Configurable { +public final class HttpServlet3Instrumentation extends Instrumenter.Default { public static final String SERVLET_OPERATION_NAME = "servlet.request"; public HttpServlet3Instrumentation() { super("servlet", "servlet-3"); } - //, - // classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener") + @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.http.HttpServlet"))))) - .transform( - new HelperInjector( - "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter", - "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", - HttpServlet3Advice.class.getName() + "$TagSettingAsyncListener")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - named("service") - .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) - .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) - .and(isProtected()), - HttpServlet3Advice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + // + // classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener") + return not(isInterface()).and(failSafe(hasSuperType(named("javax.servlet.http.HttpServlet")))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter", + "datadog.trace.instrumentation.servlet3.HttpServletRequestExtractAdapter$MultivaluedMapFlatIterator", + HttpServlet3Advice.class.getName() + "$TagSettingAsyncListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("service") + .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))) + .and(takesArgument(1, named("javax.servlet.http.HttpServletResponse"))) + .and(isProtected()), + HttpServlet3Advice.class.getName()); + return transformers; } public static class HttpServlet3Advice { diff --git a/dd-java-agent/instrumentation/sparkjava-2.4/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java b/dd-java-agent/instrumentation/sparkjava-2.4/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java index 6856ea3d56..6b292b5111 100644 --- a/dd-java-agent/instrumentation/sparkjava-2.4/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java +++ b/dd-java-agent/instrumentation/sparkjava-2.4/src/main/java/datadog/trace/instrumentation/sparkjava/RoutesInstrumentation.java @@ -6,18 +6,19 @@ import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDTags; import io.opentracing.Scope; import io.opentracing.util.GlobalTracer; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import spark.route.HttpMethod; import spark.routematch.RouteMatch; @AutoService(Instrumenter.class) -public class RoutesInstrumentation extends Instrumenter.Configurable { +public class RoutesInstrumentation extends Instrumenter.Default { public RoutesInstrumentation() { super("sparkjava", "sparkjava-2.4"); @@ -29,18 +30,20 @@ public class RoutesInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(named("spark.route.Routes")) - .transform( - DDAdvice.create() - .advice( - named("find") - .and(takesArgument(0, named("spark.route.HttpMethod"))) - .and(returns(named("spark.routematch.RouteMatch"))) - .and(isPublic()), - RoutesAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("spark.route.Routes"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + named("find") + .and(takesArgument(0, named("spark.route.HttpMethod"))) + .and(returns(named("spark.routematch.RouteMatch"))) + .and(isPublic()), + RoutesAdvice.class.getName()); + return transformers; } public static class RoutesAdvice { diff --git a/dd-java-agent/instrumentation/spring-web/src/main/java/datadog/trace/instrumentation/springweb/SpringWebInstrumentation.java b/dd-java-agent/instrumentation/spring-web/src/main/java/datadog/trace/instrumentation/springweb/SpringWebInstrumentation.java index 5e82cb2998..be53bc2091 100644 --- a/dd-java-agent/instrumentation/spring-web/src/main/java/datadog/trace/instrumentation/springweb/SpringWebInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-web/src/main/java/datadog/trace/instrumentation/springweb/SpringWebInstrumentation.java @@ -14,8 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDTags; @@ -24,48 +22,67 @@ import io.opentracing.Span; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.servlet.http.HttpServletRequest; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import org.springframework.web.servlet.HandlerMapping; @AutoService(Instrumenter.class) -public final class SpringWebInstrumentation extends Instrumenter.Configurable { +public final class SpringWebInstrumentation extends Instrumenter.Default { public SpringWebInstrumentation() { super("spring-web"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - not(isInterface()) - .and( - failSafe( - hasSuperType(named("org.springframework.web.servlet.HandlerAdapter")))), - classLoaderHasClassWithField( - "org.springframework.web.servlet.HandlerMapping", - "BEST_MATCHING_PATTERN_ATTRIBUTE")) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(nameStartsWith("handle")) - .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))), - SpringWebNamingAdvice.class.getName())) - .type(not(isInterface()).and(named("org.springframework.web.servlet.DispatcherServlet"))) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isProtected()) - .and(nameStartsWith("processHandlerException")) - .and(takesArgument(3, Exception.class)), - SpringWebErrorHandlerAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return not(isInterface()) + .and(failSafe(hasSuperType(named("org.springframework.web.servlet.HandlerAdapter")))); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return classLoaderHasClassWithField( + "org.springframework.web.servlet.HandlerMapping", "BEST_MATCHING_PATTERN_ATTRIBUTE"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(nameStartsWith("handle")) + .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))), + SpringWebNamingAdvice.class.getName()); + return transformers; + } + + @AutoService(Instrumenter.class) + public static class DispatcherServletInstrumentation extends Default { + + public DispatcherServletInstrumentation() { + super("spring-web"); + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(named("org.springframework.web.servlet.DispatcherServlet")); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isProtected()) + .and(nameStartsWith("processHandlerException")) + .and(takesArgument(3, Exception.class)), + SpringWebErrorHandlerAdvice.class.getName()); + return transformers; + } } public static class SpringWebNamingAdvice { diff --git a/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java b/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java index 3df5b09a8c..c3cc01de82 100644 --- a/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java +++ b/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java @@ -4,82 +4,80 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClass import static net.bytebuddy.matcher.ElementMatchers.*; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import io.opentracing.util.GlobalTracer; import java.lang.reflect.Method; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; import net.spy.memcached.MemcachedClient; import net.spy.memcached.internal.BulkFuture; import net.spy.memcached.internal.GetFuture; import net.spy.memcached.internal.OperationFuture; @AutoService(Instrumenter.class) -public final class MemcachedClientInstrumentation extends Instrumenter.Configurable { +public final class MemcachedClientInstrumentation extends Instrumenter.Default { private static final String MEMCACHED_PACKAGE = "net.spy.memcached"; private static final String HELPERS_PACKAGE = MemcachedClientInstrumentation.class.getPackage().getName(); - public static final HelperInjector HELPER_INJECTOR = - new HelperInjector( - HELPERS_PACKAGE + ".CompletionListener", - HELPERS_PACKAGE + ".GetCompletionListener", - HELPERS_PACKAGE + ".OperationCompletionListener", - HELPERS_PACKAGE + ".BulkGetCompletionListener"); + public static final HelperInjector HELPER_INJECTOR = new HelperInjector(); public MemcachedClientInstrumentation() { super("spymemcached"); } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type( - named(MEMCACHED_PACKAGE + ".MemcachedClient"), - // Target 2.12 that has this method - classLoaderHasClassWithMethod( - MEMCACHED_PACKAGE + ".ConnectionFactoryBuilder", - "setListenerExecutorService", - "java.util.concurrent.ExecutorService")) - .transform(HELPER_INJECTOR) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(returns(named(MEMCACHED_PACKAGE + ".internal.OperationFuture"))) - /* - Flush seems to have a bug when listeners may not be always called. - Also tracing flush is probably of a very limited value. - */ - .and(not(named("flush"))), - AsyncOperationAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(returns(named(MEMCACHED_PACKAGE + ".internal.GetFuture"))), - AsyncGetAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - isMethod() - .and(isPublic()) - .and(returns(named(MEMCACHED_PACKAGE + ".internal.BulkFuture"))), - AsyncBulkAdvice.class.getName())) - .transform( - DDAdvice.create() - .advice( - isMethod().and(isPublic()).and(named("incr").or(named("decr"))), - SyncOperationAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named(MEMCACHED_PACKAGE + ".MemcachedClient"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + // Target 2.12 that has this method + return classLoaderHasClassWithMethod( + MEMCACHED_PACKAGE + ".ConnectionFactoryBuilder", + "setListenerExecutorService", + "java.util.concurrent.ExecutorService"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + HELPERS_PACKAGE + ".CompletionListener", + HELPERS_PACKAGE + ".GetCompletionListener", + HELPERS_PACKAGE + ".OperationCompletionListener", + HELPERS_PACKAGE + ".BulkGetCompletionListener" + }; + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(isPublic()) + .and(returns(named(MEMCACHED_PACKAGE + ".internal.OperationFuture"))) + /* + Flush seems to have a bug when listeners may not be always called. + Also tracing flush is probably of a very limited value. + */ + .and(not(named("flush"))), + AsyncOperationAdvice.class.getName()); + transformers.put( + isMethod().and(isPublic()).and(returns(named(MEMCACHED_PACKAGE + ".internal.GetFuture"))), + AsyncGetAdvice.class.getName()); + transformers.put( + isMethod().and(isPublic()).and(returns(named(MEMCACHED_PACKAGE + ".internal.BulkFuture"))), + AsyncBulkAdvice.class.getName()); + transformers.put( + isMethod().and(isPublic()).and(named("incr").or(named("decr"))), + SyncOperationAdvice.class.getName()); + return transformers; } @Override diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java index dbabdefe14..3d77dfe3c4 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java @@ -2,7 +2,6 @@ package datadog.trace.instrumentation.trace_annotation; import static datadog.trace.instrumentation.trace_annotation.TraceConfigInstrumentation.PACKAGE_CLASS_NAME_REGEX; import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; -import static net.bytebuddy.matcher.ElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; import static net.bytebuddy.matcher.ElementMatchers.is; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; @@ -10,21 +9,20 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import com.google.common.collect.Sets; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.Trace; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.NamedElement; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @Slf4j @AutoService(Instrumenter.class) -public final class TraceAnnotationsInstrumentation extends Instrumenter.Configurable { +public final class TraceAnnotationsInstrumentation extends Instrumenter.Default { private static final String CONFIG_NAME = "dd.trace.annotations"; static final String CONFIG_FORMAT = @@ -44,6 +42,7 @@ public final class TraceAnnotationsInstrumentation extends Instrumenter.Configur }; private final Set additionalTraceAnnotations; + private final ElementMatcher.Junction methodTraceMatcher; public TraceAnnotationsInstrumentation() { super("trace", "trace-annotation"); @@ -69,21 +68,24 @@ public final class TraceAnnotationsInstrumentation extends Instrumenter.Configur } additionalTraceAnnotations = Collections.unmodifiableSet(annotations); } - } - @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { ElementMatcher.Junction methodTraceMatcher = is(new TypeDescription.ForLoadedType(Trace.class)); for (final String annotationName : additionalTraceAnnotations) { methodTraceMatcher = methodTraceMatcher.or(named(annotationName)); } - return agentBuilder - .type(failSafe(hasSuperType(declaresMethod(isAnnotatedWith(methodTraceMatcher))))) - .transform(DDTransformers.defaultTransformers()) - .transform( - DDAdvice.create() - .advice(isAnnotatedWith(methodTraceMatcher), TraceAdvice.class.getName())) - .asDecorator(); + this.methodTraceMatcher = methodTraceMatcher; + } + + @Override + public ElementMatcher typeMatcher() { + return hasSuperType(declaresMethod(isAnnotatedWith(methodTraceMatcher))); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put(isAnnotatedWith(methodTraceMatcher), TraceAdvice.class.getName()); + return transformers; } } diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java index 410ca244e2..502eef6bdd 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java @@ -6,19 +6,20 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import datadog.trace.agent.tooling.DDAdvice; import datadog.trace.agent.tooling.Instrumenter; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Set; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @Slf4j @AutoService(Instrumenter.class) -public class TraceConfigInstrumentation extends Instrumenter.Configurable { +public class TraceConfigInstrumentation extends Instrumenter.Default { private static final String CONFIG_NAME = "dd.trace.methods"; static final String PACKAGE_CLASS_NAME_REGEX = "[\\w.\\$]+"; @@ -78,28 +79,59 @@ public class TraceConfigInstrumentation extends Instrumenter.Configurable { } @Override - public AgentBuilder apply(final AgentBuilder agentBuilder) { + public AgentBuilder instrument(AgentBuilder agentBuilder) { if (classMethodsToTrace.isEmpty()) { return agentBuilder; } - AgentBuilder builder = agentBuilder; for (final Map.Entry> entry : classMethodsToTrace.entrySet()) { + TracerClassInstrumentation tracerConfigClass = + new TracerClassInstrumentation(entry.getKey(), entry.getValue()); + agentBuilder = tracerConfigClass.instrument(agentBuilder); + } + return agentBuilder; + } + // Not Using AutoService to hook up this instrumentation + public static class TracerClassInstrumentation extends Default { + private final String className; + private final Set methodNames; + + public TracerClassInstrumentation(String className, Set methodNames) { + super("trace", "trace-config"); + this.className = className; + this.methodNames = methodNames; + } + + @Override + public ElementMatcher typeMatcher() { + return hasSuperType(named(className)); + } + + @Override + public Map transformers() { ElementMatcher.Junction methodMatchers = null; - for (final String methodName : entry.getValue()) { + for (final String methodName : methodNames) { if (methodMatchers == null) { methodMatchers = named(methodName); } else { methodMatchers = methodMatchers.or(named(methodName)); } } - builder = - builder - .type(hasSuperType(named(entry.getKey()))) - .transform(DDAdvice.create().advice(methodMatchers, TraceAdvice.class.getName())) - .asDecorator(); + + Map transformers = new HashMap<>(); + transformers.put(methodMatchers, TraceAdvice.class.getName()); + return transformers; } - return builder; + } + + @Override + public ElementMatcher typeMatcher() { + throw new RuntimeException("TracerConfigInstrumentation must not use TypeMatcher"); + } + + @Override + public Map transformers() { + throw new RuntimeException("TracerConfigInstrumentation must not use transformers."); } } diff --git a/dd-java-agent/testing/src/test/java/IBMResourceLevelInstrumentation.java b/dd-java-agent/testing/src/test/java/IBMResourceLevelInstrumentation.java index 19761de49d..f08c57d064 100644 --- a/dd-java-agent/testing/src/test/java/IBMResourceLevelInstrumentation.java +++ b/dd-java-agent/testing/src/test/java/IBMResourceLevelInstrumentation.java @@ -1,25 +1,28 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.DDAdvice; -import datadog.trace.agent.tooling.DDTransformers; import datadog.trace.agent.tooling.Instrumenter; -import net.bytebuddy.agent.builder.AgentBuilder; +import java.util.HashMap; +import java.util.Map; import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(Instrumenter.class) -public class IBMResourceLevelInstrumentation extends Instrumenter.Configurable { +public class IBMResourceLevelInstrumentation extends Instrumenter.Default { public IBMResourceLevelInstrumentation() { super(IBMResourceLevelInstrumentation.class.getName()); } @Override - protected AgentBuilder apply(final AgentBuilder agentBuilder) { - return agentBuilder - .type(named("com.ibm.as400.resource.ResourceLevel")) - .transform(DDTransformers.defaultTransformers()) - .transform(DDAdvice.create().advice(named("toString"), ToStringAdvice.class.getName())) - .asDecorator(); + public ElementMatcher typeMatcher() { + return named("com.ibm.as400.resource.ResourceLevel"); + } + + @Override + public Map transformers() { + Map transformers = new HashMap<>(); + transformers.put(named("toString"), ToStringAdvice.class.getName()); + return transformers; } public static class ToStringAdvice {