New Instrumentation API

This commit is contained in:
Andrew Kent 2018-06-20 15:25:47 -07:00
parent 33a139cdcb
commit 02a3e6a5d3
62 changed files with 1985 additions and 1722 deletions

View File

@ -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.
*
* <p>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<? super ClassLoader> classLoaderMatcher();
/** @return Class names of helpers to inject into the user's classloader */
String[] helperClassNames();
Map<ElementMatcher, String> transformers();
@Slf4j
abstract class Configurable implements Instrumenter {
abstract class Default implements Instrumenter {
private final Set<String> 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<ElementMatcher, String> 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<? super ClassLoader> classLoaderMatcher() {
return any();
}
@Override
public abstract ElementMatcher<? super TypeDescription> typeMatcher();
@Override
public abstract Map<ElementMatcher, String> 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)));

View File

@ -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<? super TypeDescription> getTypeMatcher();
/**
* @return A type matcher used to match the classloader under transform
*/
ElementMatcher<? super ClassLoaderMatcher> getClassLoaderMatcher();
/**
*
* @return
*/
Set<String> getHelperClassNames();
Map<ElementMatcher, String> 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(), <all-cl>)
.and(safeToInject()) // implementation generated by muzzle
.transform(DDTransformers.defaultTransformers())
.transform(new HelperInjector(getHelperClassNames()));
Map<ElementMatcher, String> advice = getTransformers();
for (Entry<ElementMatcher, String> entry : advice.getEntrySet()) {
transformer = transformer.transform(DDAdvice.create().advice(entry.getKey(), entry.getValue()));
}
return transformer.asDecorator()
*/
// FIXME
return null;
}
@Override
public Set<String> getHelperClassNames() {
// FIXME
return null;
}
public abstract ElementMatcher<? super TypeDescription> getTypeMatcher();
public abstract ElementMatcher<? super ClassLoaderMatcher> getClassLoaderMatcher();
public abstract Map<ElementMatcher, String> getTransformers();
// TODO merge in config logic from previous instrumenter
private final Set<String> 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(".", "_");
}
}
}

View File

@ -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<? super TypeDescription> typeMatcher() {
applyCalled = true
return new ElementMatcher() {
@Override
boolean matches(Object target) {
return false
}
}
}
@Override
Map<ElementMatcher, String> transformers() {
return Collections.emptyMap()
}
}
}

View File

@ -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<? super TypeDescription> 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<ElementMatcher, String> 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<ElementMatcher, String> 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 {

View File

@ -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<? super TypeDescription> typeMatcher() {
return named("org.apache.http.impl.client.HttpClientBuilder");
}
@Override
public ElementMatcher<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(named("decorateProtocolExec")), ApacheHttpClientAdvice.class.getName());
return transformers;
}
public static class ApacheHttpClientAdvice {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(isConstructor(), AWSClientAdvice.class.getName());
return transformers;
}
public static class AWSClientAdvice {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(isConstructor(), AWSClientAdvice.class.getName());
return transformers;
}
public static class AWSClientAdvice {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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);

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(isPrivate()).and(named("newSession")).and(takesArguments(0)),
CassandraClientAdvice.class.getName());
return transformers;
}
public static class CassandraClientAdvice {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(isPublic()).and(named("openConnection")),
ConnectionErrorAdvice.class.getName());
return transformers;
}
public static class ConnectionErrorAdvice {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(named("run").or(named("getFallback"))), TraceAdvice.class.getName());
return transformers;
}
public static class TraceAdvice {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("com.netflix.hystrix.AbstractCommand");
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(named("schedule")).and(takesArguments(1)),
EnableAsyncAdvice.class.getName());
return transformers;
}
public static class EnableAsyncAdvice {

View File

@ -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<TypeDescription>() {
@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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<TypeDescription>() {
@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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
named("cancel").and(returns(boolean.class)), CanceledFutureAdvice.class.getName());
return transformers;
}
public static class CanceledFutureAdvice {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
return Collections.emptyMap();
}
}

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
nameStartsWith("execute").and(takesArguments(0)).and(isPublic()),
PreparedStatementAdvice.class.getName());
return transformers;
}
public static class PreparedStatementAdvice {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
nameStartsWith("execute").and(takesArgument(0, String.class)).and(isPublic()),
StatementAdvice.class.getName());
return transformers;
}
public static class StatementAdvice {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("redis.clients.jedis.Protocol$Command");
}
@Override
public String[] helperClassNames() {
return new String[] {};
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super TypeDescription> typeMatcher() {
return not(isInterface()).and(hasSuperType(named("javax.jms.MessageConsumer")));
}
@Override
public ElementMatcher<? super ClassLoader> classLoaderMatcher() {
return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"));
}
@Override
public String[] helperClassNames() {
return JMS1_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"));
}
@Override
public String[] helperClassNames() {
return JMS1MessageConsumerInstrumentation.JMS1_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"));
}
@Override
public String[] helperClassNames() {
return JMS1MessageConsumerInstrumentation.JMS1_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener");
}
@Override
public String[] helperClassNames() {
return JMS2_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener");
}
@Override
public String[] helperClassNames() {
return JMS2MessageConsumerInstrumentation.JMS2_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener");
}
@Override
public String[] helperClassNames() {
return JMS2MessageConsumerInstrumentation.JMS2_HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("org.apache.jasper.servlet.JspServletWrapper");
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
named("compile").and(takesArguments(0)).and(isPublic()),
JasperJspCompilationContext.class.getName());
return transformers;
}
public static class JasperJspCompilationContext {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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
]
}

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("org.apache.kafka.streams.state.internals.OrderedBytes");
}
@Override
public String[] helperClassNames() {
return HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(isPublic()).and(named("process")).and(takesArguments(0)),
StopSpanAdvice.class.getName());
return transformers;
}
public static class StopSpanAdvice {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("org.apache.kafka.streams.state.internals.OrderedBytes");
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(named("dispatch"))
.and(takesArgument(0, named("io.lettuce.core.protocol.RedisCommand"))),
LettuceAsyncCommandsAdvice.class.getName());
return transformers;
}
}

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClasses("io.lettuce.core.RedisClient");
}
@Override
public String[] helperClassNames() {
return HELPER_CLASS_NAMES;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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;
}
}

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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;
}
}

View File

@ -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.<TypeDescription.Generic>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.<TypeDescription.Generic>emptyList())))
.and(isPublic())));
}
@Override
public String[] helperClassNames() {
return HELPERS;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)),
MongoClientAdvice.class.getName());
return transformers;
}
public static class MongoClientAdvice {

View File

@ -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.<TypeDescription.Generic>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.<TypeDescription.Generic>emptyList())))
.and(isPublic())));
}
@Override
public String[] helperClassNames() {
return MongoClientInstrumentation.HELPERS;
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)),
MongoAsyncClientAdvice.class.getName());
return transformers;
}
public static class MongoAsyncClientAdvice {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(nameStartsWith("add"))
.and(takesArgument(2, named("io.netty.channel.ChannelHandler"))),
ChannelPipelineAddAdvice.class.getName());
return transformers;
}
/**

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(nameStartsWith("add"))
.and(takesArgument(2, named("io.netty.channel.ChannelHandler"))),
ChannelPipelineAddAdvice.class.getName());
return transformers;
}
/**

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isConstructor().and(takesArgument(0, named("okhttp3.OkHttpClient$Builder"))),
OkHttp3Advice.class.getName());
return transformers;
}
public static class OkHttp3Advice {

View File

@ -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<ElementMatcher, String> transformers() {
return Collections.emptyMap();
}
}

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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;
}
}

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
named("fork").and(returns(named("ratpack.exec.ExecStarter"))),
RatpackServerAdvice.ExecutionAdvice.class.getName());
return transformers;
}
}
}

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> classLoaderMatcher() {
return classLoaderHasClassWithField(
"org.springframework.web.servlet.HandlerMapping", "BEST_MATCHING_PATTERN_ATTRIBUTE");
}
@Override
public Map<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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 {

View File

@ -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<? super ClassLoader> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> 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

View File

@ -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<String> additionalTraceAnnotations;
private final ElementMatcher.Junction<NamedElement> 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<NamedElement> 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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(isAnnotatedWith(methodTraceMatcher), TraceAdvice.class.getName());
return transformers;
}
}

View File

@ -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<String, Set<String>> 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<String> methodNames;
public TracerClassInstrumentation(String className, Set<String> methodNames) {
super("trace", "trace-config");
this.className = className;
this.methodNames = methodNames;
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return hasSuperType(named(className));
}
@Override
public Map<ElementMatcher, String> transformers() {
ElementMatcher.Junction<MethodDescription> 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<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(methodMatchers, TraceAdvice.class.getName());
return transformers;
}
return builder;
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
throw new RuntimeException("TracerConfigInstrumentation must not use TypeMatcher");
}
@Override
public Map<ElementMatcher, String> transformers() {
throw new RuntimeException("TracerConfigInstrumentation must not use transformers.");
}
}

View File

@ -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<ElementMatcher, String> transformers() {
Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(named("toString"), ToStringAdvice.class.getName());
return transformers;
}
public static class ToStringAdvice {