Initial finatra instrumentation
This commit is contained in:
parent
5c6f74fd5e
commit
4e58643bd0
|
@ -0,0 +1,42 @@
|
||||||
|
// Set properties before any plugins get loaded
|
||||||
|
ext {
|
||||||
|
minJavaVersionForTests = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
apply from: "${rootDir}/gradle/test-with-scala.gradle"
|
||||||
|
|
||||||
|
// apply plugin: 'org.unbroken-dome.test-sets'
|
||||||
|
//testSets {
|
||||||
|
//
|
||||||
|
// latestDepTest {
|
||||||
|
// dirName = 'test'
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
muzzle {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly group: 'com.twitter', name: 'finagle-http_2.11', version: '19.1.0'
|
||||||
|
compileOnly group: 'com.twitter', name: 'finatra-http_2.11', version: '19.1.0'
|
||||||
|
|
||||||
|
testCompile project(':dd-java-agent:instrumentation:netty-4.1')
|
||||||
|
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
|
||||||
|
testCompile project(':dd-java-agent:instrumentation:trace-annotation')
|
||||||
|
|
||||||
|
testCompile group: 'com.twitter', name: 'finagle-http_2.11', version: '19.1.0'
|
||||||
|
|
||||||
|
testCompile(group: 'com.fasterxml.jackson.module', name: 'jackson-module-scala_2.11', version: '2.10.2') {
|
||||||
|
force = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// latestDepTestCompile project(':dd-java-agent:instrumentation:java-concurrent')
|
||||||
|
// latestDepTestCompile project(':dd-java-agent:instrumentation:trace-annotation')
|
||||||
|
}
|
||||||
|
|
||||||
|
//compileLatestDepTestGroovy {
|
||||||
|
// classpath = classpath.plus(files(compileLatestDepTestScala.destinationDir))
|
||||||
|
// dependsOn compileLatestDepTestScala
|
||||||
|
//}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package datadog.trace.instrumentation.finatra;
|
||||||
|
|
||||||
|
import com.twitter.finagle.http.Request;
|
||||||
|
import com.twitter.finagle.http.Response;
|
||||||
|
import datadog.trace.agent.decorator.HttpServerDecorator;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
public class FinatraDecorator extends HttpServerDecorator<Request, Request, Response> {
|
||||||
|
public static final FinatraDecorator DECORATE = new FinatraDecorator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "finatra";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(final Request request) {
|
||||||
|
return request.method().name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URI url(final Request request) throws URISyntaxException {
|
||||||
|
return URI.create(request.uri());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String peerHostname(final Request request) {
|
||||||
|
return request.remoteHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String peerHostIP(final Request request) {
|
||||||
|
return request.remoteAddress().getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer peerPort(final Request request) {
|
||||||
|
return request.remotePort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer status(final Response response) {
|
||||||
|
return response.statusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return new String[] {"finatra"};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package datadog.trace.instrumentation.finatra;
|
||||||
|
|
||||||
|
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||||
|
import static datadog.trace.instrumentation.api.AgentTracer.activateSpan;
|
||||||
|
import static datadog.trace.instrumentation.api.AgentTracer.activeSpan;
|
||||||
|
import static datadog.trace.instrumentation.api.AgentTracer.startSpan;
|
||||||
|
import static datadog.trace.instrumentation.finatra.FinatraDecorator.DECORATE;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
import com.twitter.finagle.http.Request;
|
||||||
|
import com.twitter.finagle.http.Response;
|
||||||
|
import com.twitter.util.Future;
|
||||||
|
import com.twitter.util.FutureEventListener;
|
||||||
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import datadog.trace.instrumentation.api.AgentScope;
|
||||||
|
import datadog.trace.instrumentation.api.AgentSpan;
|
||||||
|
import datadog.trace.instrumentation.api.Tags;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
import scala.Some;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public class FinatraInstrumentation extends Instrumenter.Default {
|
||||||
|
public FinatraInstrumentation() {
|
||||||
|
super("finatra");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
"datadog.trace.agent.decorator.BaseDecorator",
|
||||||
|
"datadog.trace.agent.decorator.ServerDecorator",
|
||||||
|
"datadog.trace.agent.decorator.HttpServerDecorator",
|
||||||
|
packageName + ".FinatraDecorator",
|
||||||
|
FinatraInstrumentation.class.getName() + "$Listener"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<? super TypeDescription> typeMatcher() {
|
||||||
|
return not(isInterface())
|
||||||
|
.and(safeHasSuperType(named("com.twitter.finatra.http.internal.routing.Route")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
|
return singletonMap(
|
||||||
|
isMethod()
|
||||||
|
.and(named("handleMatch"))
|
||||||
|
.and(takesArguments(2))
|
||||||
|
.and(takesArgument(0, named("com.twitter.finagle.http.Request"))),
|
||||||
|
FinatraInstrumentation.class.getName() + "$RouteAdvice");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RouteAdvice {
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AgentScope nameSpan(
|
||||||
|
@Advice.Argument(0) final Request request,
|
||||||
|
@Advice.FieldValue("path") final String path,
|
||||||
|
@Advice.FieldValue("clazz") final Class clazz,
|
||||||
|
@Advice.Origin final Method method) {
|
||||||
|
|
||||||
|
final AgentSpan parent = activeSpan();
|
||||||
|
|
||||||
|
final AgentSpan span = startSpan("finatra.request");
|
||||||
|
DECORATE.afterStart(span);
|
||||||
|
DECORATE.onConnection(span, request);
|
||||||
|
DECORATE.onRequest(span, request);
|
||||||
|
|
||||||
|
if (parent != null && "netty.request".equals(parent.getSpanName())) {
|
||||||
|
parent.setTag(DDTags.RESOURCE_NAME, request.method().name() + " " + path);
|
||||||
|
parent.setTag(Tags.COMPONENT, "finatra");
|
||||||
|
parent.setSpanName("finatra.request");
|
||||||
|
|
||||||
|
span.setSpanName("finatra.controller");
|
||||||
|
span.setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForClass(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
final AgentScope scope = activateSpan(span, false);
|
||||||
|
scope.setAsyncPropagation(true);
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class)
|
||||||
|
public static void setupCallback(
|
||||||
|
@Advice.Enter final AgentScope scope,
|
||||||
|
@Advice.Thrown final Throwable throwable,
|
||||||
|
@Advice.Return final Some<Future<Response>> responseOption) {
|
||||||
|
|
||||||
|
if (scope == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AgentSpan span = scope.span();
|
||||||
|
if (throwable != null) {
|
||||||
|
DECORATE.onError(span, throwable);
|
||||||
|
DECORATE.beforeFinish(span);
|
||||||
|
span.finish();
|
||||||
|
scope.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseOption.get().addEventListener(new Listener(scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Listener implements FutureEventListener<Response> {
|
||||||
|
private final AgentScope scope;
|
||||||
|
|
||||||
|
public Listener(final AgentScope scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final Response response) {
|
||||||
|
DECORATE.onResponse(scope.span(), response);
|
||||||
|
DECORATE.beforeFinish(scope.span());
|
||||||
|
scope.span().finish();
|
||||||
|
scope.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(final Throwable cause) {
|
||||||
|
DECORATE.onError(scope.span(), cause);
|
||||||
|
DECORATE.beforeFinish(scope.span());
|
||||||
|
scope.span().finish();
|
||||||
|
scope.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,12 +44,22 @@ public class ExecutorInstrumentationUtils {
|
||||||
*/
|
*/
|
||||||
public static <T> State setupState(
|
public static <T> State setupState(
|
||||||
final ContextStore<T, State> contextStore, final T task, final TraceScope scope) {
|
final ContextStore<T, State> contextStore, final T task, final TraceScope scope) {
|
||||||
|
|
||||||
final State state = contextStore.putIfAbsent(task, State.FACTORY);
|
final State state = contextStore.putIfAbsent(task, State.FACTORY);
|
||||||
final TraceScope.Continuation continuation = scope.capture();
|
|
||||||
if (state.setContinuation(continuation)) {
|
// Don't instrument the executor's own runnables. These runnables may never return until
|
||||||
log.debug("created continuation {} from scope {}, state: {}", continuation, scope, state);
|
// netty shuts down. Any created continuations will be open until that time preventing traces
|
||||||
} else {
|
// from being reported
|
||||||
continuation.close(false);
|
if (!task.getClass()
|
||||||
|
.getName()
|
||||||
|
.startsWith("io.netty.util.concurrent.SingleThreadEventExecutor$")) {
|
||||||
|
|
||||||
|
final TraceScope.Continuation continuation = scope.capture();
|
||||||
|
if (state.setContinuation(continuation)) {
|
||||||
|
log.debug("created continuation {} from scope {}, state: {}", continuation, scope, state);
|
||||||
|
} else {
|
||||||
|
continuation.close(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ include ':dd-java-agent:instrumentation:elasticsearch:transport-2'
|
||||||
include ':dd-java-agent:instrumentation:elasticsearch:transport-5'
|
include ':dd-java-agent:instrumentation:elasticsearch:transport-5'
|
||||||
include ':dd-java-agent:instrumentation:elasticsearch:transport-5.3'
|
include ':dd-java-agent:instrumentation:elasticsearch:transport-5.3'
|
||||||
include ':dd-java-agent:instrumentation:elasticsearch:transport-6'
|
include ':dd-java-agent:instrumentation:elasticsearch:transport-6'
|
||||||
|
include ':dd-java-agent:instrumentation:finatra'
|
||||||
include ':dd-java-agent:instrumentation:glassfish'
|
include ':dd-java-agent:instrumentation:glassfish'
|
||||||
include ':dd-java-agent:instrumentation:google-http-client'
|
include ':dd-java-agent:instrumentation:google-http-client'
|
||||||
include ':dd-java-agent:instrumentation:grizzly-2'
|
include ':dd-java-agent:instrumentation:grizzly-2'
|
||||||
|
|
Loading…
Reference in New Issue