Merge pull request #168 from DataDog/ark/spring-boot-classloaders
Enhance Support for spring-boot classloader
This commit is contained in:
commit
ae2b85ea51
|
@ -0,0 +1,103 @@
|
|||
package com.datadoghq.agent;
|
||||
|
||||
import com.datadoghq.trace.Trace;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.UUID;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ClassLoaderTest {
|
||||
|
||||
/** Assert that we can instrument classloaders which cannot resolve agent advice classes. */
|
||||
@Test
|
||||
public void instrumentClassLoadersWithoutAgentClasses() throws Exception {
|
||||
URL[] classpath = new URL[] {createJarWithClasses(ClassToInstrument.class, Trace.class)};
|
||||
URLClassLoader loader = new URLClassLoader(classpath, null);
|
||||
|
||||
try {
|
||||
loader.loadClass("com.datadoghq.agent.TracingAgent");
|
||||
Assert.fail("loader should not see agent classes.");
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
// Good. loader can't see agent classes.
|
||||
}
|
||||
|
||||
Class<?> instrumentedClass = loader.loadClass(ClassToInstrument.class.getName());
|
||||
Assert.assertEquals(
|
||||
"Class must be loaded by loader.", loader, instrumentedClass.getClassLoader());
|
||||
|
||||
final Class<?> rulesManagerClass =
|
||||
Class.forName(
|
||||
"com.datadoghq.agent.InstrumentationRulesManager",
|
||||
true,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
Method isRegisteredMethod = rulesManagerClass.getMethod("isRegistered", Object.class);
|
||||
Assert.assertTrue(
|
||||
"Agent did not initialized loader.", (boolean) isRegisteredMethod.invoke(null, loader));
|
||||
loader.close();
|
||||
}
|
||||
|
||||
/** com.foo.Bar -> com/foo/Bar.class */
|
||||
public static String getResourceName(Class<?> clazz) {
|
||||
return clazz.getName().replace('.', '/') + ".class";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temporary jar on the filesystem with the bytes of the given classes.
|
||||
*
|
||||
* <p>The jar file will be removed when the jvm exits.
|
||||
*
|
||||
* @param classes classes to package into the jar.
|
||||
* @return the location of the newly created jar.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static URL createJarWithClasses(Class<?>... classes) throws IOException {
|
||||
final File tmpJar = File.createTempFile(UUID.randomUUID() + "", ".jar");
|
||||
tmpJar.deleteOnExit();
|
||||
|
||||
final Manifest manifest = new Manifest();
|
||||
JarOutputStream target = new JarOutputStream(new FileOutputStream(tmpJar), manifest);
|
||||
for (Class<?> clazz : classes) {
|
||||
addToJar(clazz, target);
|
||||
}
|
||||
target.close();
|
||||
|
||||
return tmpJar.toURI().toURL();
|
||||
}
|
||||
|
||||
private static void addToJar(Class<?> clazz, JarOutputStream jarOutputStream) throws IOException {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
JarEntry entry = new JarEntry(getResourceName(clazz));
|
||||
jarOutputStream.putNextEntry(entry);
|
||||
inputStream = clazz.getClassLoader().getResourceAsStream(getResourceName(clazz));
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
while (true) {
|
||||
int count = inputStream.read(buffer);
|
||||
if (count == -1) {
|
||||
break;
|
||||
}
|
||||
jarOutputStream.write(buffer, 0, count);
|
||||
}
|
||||
jarOutputStream.closeEntry();
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassToInstrument {
|
||||
@Trace
|
||||
public static void someMethod() {}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package dd.inst.apachehttpclient;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
import com.datadoghq.agent.integration.DDTracingClientExec;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
|
@ -32,11 +32,10 @@ public class ApacheHttpClientInstrumentation implements Instrumenter {
|
|||
"org.apache.http.conn.routing.HttpRoute",
|
||||
"org.apache.http.impl.execchain.ClientExecChain"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
isMethod().and(named("decorateProtocolExec")),
|
||||
ApacheHttpClientAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ApacheHttpClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dd.inst.aws;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
@ -9,6 +8,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.contrib.aws.TracingRequestHandler;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
|
@ -30,11 +30,10 @@ public final class AWSClientInstrumentation implements Instrumenter {
|
|||
"com.amazonaws.http.client.HttpClientFactory",
|
||||
"com.amazonaws.http.apache.utils.ApacheUtils"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("build").and(takesArguments(0)).and(isPublic()),
|
||||
AWSClientAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
AWSClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package dd.inst.datastax.cassandra;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.Tracer;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
|
@ -36,11 +36,10 @@ public class CassandraClientInstrumentation implements Instrumenter {
|
|||
"com.google.common.util.concurrent.Futures",
|
||||
"com.google.common.util.concurrent.ListenableFuture"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
isMethod().and(isPrivate()).and(named("newSession")).and(takesArguments(0)),
|
||||
CassandraClientAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
CassandraClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms1;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -36,14 +36,13 @@ public final class JMS1MessageConsumerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageConsumer"))),
|
||||
not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("receive").and(takesArguments(0)).and(isPublic()),
|
||||
ConsumerAdvice.class.getName())
|
||||
.advice(
|
||||
named("receiveNoWait").and(takesArguments(0)).and(isPublic()),
|
||||
ConsumerAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ConsumerAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms1;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -35,13 +35,12 @@ public final class JMS1MessageListenerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageListener"))),
|
||||
not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("onMessage")
|
||||
.and(takesArgument(0, named("javax.jms.Message")))
|
||||
.and(isPublic()),
|
||||
MessageListenerAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
MessageListenerAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms1;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.propagation.Format;
|
||||
|
@ -36,7 +36,7 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageProducer"))),
|
||||
not(classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener")))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()),
|
||||
ProducerAdvice.class.getName())
|
||||
|
@ -45,8 +45,7 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
|||
.and(takesArgument(0, named("javax.jms.Destination")))
|
||||
.and(takesArgument(1, named("javax.jms.Message")))
|
||||
.and(isPublic()),
|
||||
ProducerWithDestinationAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ProducerWithDestinationAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms2;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -36,14 +36,13 @@ public final class JMS2MessageConsumerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageConsumer"))),
|
||||
classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("receive").and(takesArguments(0)).and(isPublic()),
|
||||
ConsumerAdvice.class.getName())
|
||||
.advice(
|
||||
named("receiveNoWait").and(takesArguments(0)).and(isPublic()),
|
||||
ConsumerAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ConsumerAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms2;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -35,13 +35,12 @@ public final class JMS2MessageListenerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageListener"))),
|
||||
classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("onMessage")
|
||||
.and(takesArgument(0, named("javax.jms.Message")))
|
||||
.and(isPublic()),
|
||||
MessageListenerAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
MessageListenerAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package dd.inst.jms2;
|
|||
|
||||
import static com.datadoghq.agent.integration.JmsUtil.toResourceName;
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import com.datadoghq.agent.integration.MessagePropertyTextMap;
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.propagation.Format;
|
||||
|
@ -36,7 +36,7 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
|||
not(isInterface()).and(hasSuperType(named("javax.jms.MessageProducer"))),
|
||||
classLoaderHasClasses("javax.jms.JMSContext", "javax.jms.CompletionListener"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("send").and(takesArgument(0, named("javax.jms.Message"))).and(isPublic()),
|
||||
ProducerAdvice.class.getName())
|
||||
|
@ -45,8 +45,7 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
|||
.and(takesArgument(0, named("javax.jms.Destination")))
|
||||
.and(takesArgument(1, named("javax.jms.Message")))
|
||||
.and(isPublic()),
|
||||
ProducerWithDestinationAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ProducerWithDestinationAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package dd.inst.mongo;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
import com.datadoghq.agent.integration.DDTracingCommandListener;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
@ -33,11 +33,10 @@ public final class MongoClientInstrumentation implements Instrumenter {
|
|||
null,
|
||||
new TypeDescription.Generic[] {}))))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)),
|
||||
MongoClientAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
MongoClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package dd.inst.mongo;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.*;
|
||||
|
||||
import com.datadoghq.agent.integration.DDTracingCommandListener;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mongodb.async.client.MongoClientSettings;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
@ -33,11 +33,10 @@ public final class MongoAsyncClientInstrumentation implements Instrumenter {
|
|||
null,
|
||||
new TypeDescription.Generic[] {}))))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)),
|
||||
MongoAsyncClientAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
MongoAsyncClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package dd.inst.servlet2;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -36,14 +36,13 @@ public final class HttpServlet2Instrumentation implements Instrumenter {
|
|||
classLoaderHasClasses(
|
||||
"javax.servlet.ServletContextEvent", "javax.servlet.FilterChain")))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("service")
|
||||
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest")))
|
||||
.and(takesArgument(1, named("javax.servlet.http.HttpServletResponse")))
|
||||
.and(isProtected()),
|
||||
HttpServlet2Advice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
HttpServlet2Advice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package dd.inst.servlet3;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.SpanContext;
|
||||
|
@ -36,14 +36,13 @@ public final class HttpServlet3Instrumentation implements Instrumenter {
|
|||
named("javax.servlet.http.HttpServlet"),
|
||||
classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
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())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
HttpServlet3Advice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dd.inst.springweb;
|
||||
|
||||
import static dd.trace.ClassLoaderMatcher.classLoaderHasClassWithField;
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
|
@ -13,6 +12,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
|
@ -38,14 +38,13 @@ public final class SpringWebInstrumentation implements Instrumenter {
|
|||
"org.springframework.web.servlet.HandlerMapping",
|
||||
"BEST_MATCHING_PATTERN_ATTRIBUTE"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
isMethod()
|
||||
.and(isPublic())
|
||||
.and(nameStartsWith("handle"))
|
||||
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))),
|
||||
SpringWebAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
SpringWebAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,23 @@ public class InstrumentationRulesManager {
|
|||
AgentRulesManager.INSTANCE.instrumentationRulesManager.initialize(cl);
|
||||
}
|
||||
|
||||
/** True if this object's classload has been registered. */
|
||||
public static boolean isRegistered(final Object obj) {
|
||||
if (AgentRulesManager.INSTANCE == null) {
|
||||
return false;
|
||||
}
|
||||
final ClassLoader cl;
|
||||
if (obj instanceof ClassLoader) {
|
||||
cl = (ClassLoader) obj;
|
||||
} else {
|
||||
cl = obj.getClass().getClassLoader();
|
||||
}
|
||||
synchronized (cl) {
|
||||
return AgentRulesManager.INSTANCE.instrumentationRulesManager.initializedClassloaders
|
||||
.contains(cl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is separated out from initialize to allow Spring Boot's LaunchedURLClassLoader to
|
||||
* call it once it is loaded.
|
||||
|
|
|
@ -25,7 +25,6 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
|||
|
||||
import dd.trace.Instrumenter;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
@ -40,7 +39,12 @@ import net.bytebuddy.utility.JavaModule;
|
|||
@Slf4j
|
||||
public class TracingAgent {
|
||||
|
||||
public static void premain(final String agentArgs, final Instrumentation inst) throws Exception {
|
||||
/** Return the classloader the core agent is running on. */
|
||||
public static ClassLoader getAgentClassLoader() {
|
||||
return TracingAgent.class.getClassLoader();
|
||||
}
|
||||
|
||||
public static void premain(String agentArgs, final Instrumentation inst) throws Exception {
|
||||
log.debug("Using premain for loading {}", TracingAgent.class.getSimpleName());
|
||||
addByteBuddy(inst);
|
||||
AgentRulesManager.initialize();
|
||||
|
@ -111,7 +115,7 @@ public class TracingAgent {
|
|||
final JavaModule module,
|
||||
final boolean loaded,
|
||||
final DynamicType dynamicType) {
|
||||
log.debug("Transformed {}", typeDescription);
|
||||
log.debug("Transformed {} -- {}", typeDescription, classLoader);
|
||||
|
||||
if (classLoader == null) {
|
||||
return;
|
||||
|
@ -123,13 +127,9 @@ public class TracingAgent {
|
|||
initializedClassloaders.add(classLoader);
|
||||
|
||||
try {
|
||||
final Class<?> rulesManager =
|
||||
Class.forName("com.datadoghq.agent.InstrumentationRulesManager", true, classLoader);
|
||||
final Method registerClassLoad =
|
||||
rulesManager.getDeclaredMethod("registerClassLoad", Object.class);
|
||||
registerClassLoad.invoke(null, classLoader);
|
||||
InstrumentationRulesManager.registerClassLoad(classLoader);
|
||||
} catch (final Throwable e) {
|
||||
log.info("ClassLoad Registration for target " + classLoader, e);
|
||||
log.error("Failed ClassLoad Registration for target " + classLoader, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.datadoghq.agent.instrumentation.annotation;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
|
||||
|
||||
import com.datadoghq.trace.Trace;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.tag.Tags;
|
||||
|
@ -28,9 +28,7 @@ public final class TraceAnnotationInstrumentation implements Instrumenter {
|
|||
return agentBuilder
|
||||
.type(hasSuperType(declaresMethod(isAnnotatedWith(Trace.class))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
.advice(isAnnotatedWith(Trace.class), TraceAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
DDAdvice.create().advice(isAnnotatedWith(Trace.class), TraceAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.datadoghq.agent.instrumentation.jdbc;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||
|
@ -10,6 +9,7 @@ import static net.bytebuddy.matcher.ElementMatchers.returns;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -27,13 +27,12 @@ public final class ConnectionInstrumentation implements Instrumenter {
|
|||
return agentBuilder
|
||||
.type(not(isInterface()).and(hasSuperType(named(Connection.class.getName()))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
nameStartsWith("prepare")
|
||||
.and(takesArgument(0, String.class))
|
||||
.and(returns(PreparedStatement.class)),
|
||||
ConnectionAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
ConnectionAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.datadoghq.agent.instrumentation.jdbc;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
@ -8,6 +7,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
|
@ -27,11 +27,10 @@ public final class DriverInstrumentation implements Instrumenter {
|
|||
return agentBuilder
|
||||
.type(not(isInterface()).and(hasSuperType(named(Driver.class.getName()))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
named("connect").and(takesArguments(String.class, Properties.class)),
|
||||
DriverAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
DriverAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.datadoghq.agent.instrumentation.jdbc;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -11,6 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.NoopActiveSpanSource;
|
||||
|
@ -31,11 +31,10 @@ public final class PreparedStatementInstrumentation implements Instrumenter {
|
|||
return agentBuilder
|
||||
.type(not(isInterface()).and(hasSuperType(named(PreparedStatement.class.getName()))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
nameStartsWith("execute").and(takesArguments(0)).and(isPublic()),
|
||||
PreparedStatementAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
PreparedStatementAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.datadoghq.agent.instrumentation.jdbc;
|
||||
|
||||
import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
|
@ -11,6 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
|
||||
import com.datadoghq.trace.DDTags;
|
||||
import com.google.auto.service.AutoService;
|
||||
import dd.trace.DDAdvice;
|
||||
import dd.trace.Instrumenter;
|
||||
import io.opentracing.ActiveSpan;
|
||||
import io.opentracing.NoopActiveSpanSource;
|
||||
|
@ -30,11 +30,10 @@ public final class StatementInstrumentation implements Instrumenter {
|
|||
return agentBuilder
|
||||
.type(not(isInterface()).and(hasSuperType(named(Statement.class.getName()))))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
DDAdvice.create()
|
||||
.advice(
|
||||
nameStartsWith("execute").and(takesArgument(0, String.class)).and(isPublic()),
|
||||
StatementAdvice.class.getName())
|
||||
.withExceptionHandler(defaultExceptionHandler()))
|
||||
StatementAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package dd.trace;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.dynamic.ClassFileLocator;
|
||||
|
||||
/** A bytebuddy advice builder with default DataDog settings. */
|
||||
@Slf4j
|
||||
public class DDAdvice extends AgentBuilder.Transformer.ForAdvice {
|
||||
private static ClassLoader AGENT_CLASSLOADER;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> agentClass =
|
||||
DDAdvice.class.getClassLoader().loadClass("com.datadoghq.agent.TracingAgent");
|
||||
Method getAgentClassloaderMethod = agentClass.getMethod("getAgentClassLoader");
|
||||
AGENT_CLASSLOADER = (ClassLoader) getAgentClassloaderMethod.invoke(null);
|
||||
} catch (Throwable t) {
|
||||
log.error("Unable to locate agent classloader. Falling back to System Classloader");
|
||||
AGENT_CLASSLOADER = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
}
|
||||
|
||||
public static AgentBuilder.Transformer.ForAdvice create() {
|
||||
return new DDAdvice()
|
||||
.with(
|
||||
new AgentBuilder.LocationStrategy.Simple(
|
||||
ClassFileLocator.ForClassLoader.of(AGENT_CLASSLOADER)))
|
||||
.withExceptionHandler(ExceptionHandlers.defaultExceptionHandler());
|
||||
}
|
||||
|
||||
private DDAdvice() {}
|
||||
}
|
Loading…
Reference in New Issue