Add instrumentation showing the rendering time

This commit is contained in:
Tyler Benson 2018-08-09 13:10:45 +10:00
parent d05e2cfe86
commit ae9d4619a4
2 changed files with 47 additions and 13 deletions

View File

@ -1,18 +1,17 @@
package datadog.trace.instrumentation.springweb;
import static io.opentracing.log.Fields.ERROR_OBJECT;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
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 datadog.trace.agent.tooling.Instrumenter;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.util.Collections;
@ -21,32 +20,70 @@ import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.springframework.web.servlet.ModelAndView;
@AutoService(Instrumenter.class)
public final class SpringWebErrorInstrumentation extends Instrumenter.Default {
public final class DispatcherServletInstrumentation extends Instrumenter.Default {
public SpringWebErrorInstrumentation() {
public DispatcherServletInstrumentation() {
super("spring-web");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return not(isInterface()).and(named("org.springframework.web.servlet.DispatcherServlet"));
return named("org.springframework.web.servlet.DispatcherServlet");
}
@Override
public Map<ElementMatcher, String> transformers() {
final Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(isProtected())
.and(named("render"))
.and(takesArgument(0, named("org.springframework.web.servlet.ModelAndView"))),
DispatcherAdvice.class.getName());
transformers.put(
isMethod()
.and(isProtected())
.and(nameStartsWith("processHandlerException"))
.and(takesArgument(3, Exception.class)),
SpringWebErrorHandlerAdvice.class.getName());
ErrorHandlerAdvice.class.getName());
return transformers;
}
public static class SpringWebErrorHandlerAdvice {
public static class DispatcherAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope startSpan(@Advice.Argument(0) final ModelAndView mv) {
final Tracer.SpanBuilder builder =
GlobalTracer.get()
.buildSpan("response.render")
.withTag(Tags.COMPONENT.getKey(), "spring-webmvc");
if (mv.getViewName() != null) {
builder.withTag("view.name", mv.getViewName());
}
if (mv.getView() != null) {
builder.withTag("view.type", mv.getView().getClass().getName());
}
return builder.startActive(true);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
if (throwable != null) {
final Span span = scope.span();
Tags.ERROR.set(span, true);
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
}
scope.close();
}
}
public static class ErrorHandlerAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void nameResource(@Advice.Argument(3) final Exception exception) {
final Scope scope = GlobalTracer.get().scopeManager().active();

View File

@ -22,7 +22,6 @@ 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 javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
@ -35,9 +34,9 @@ import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.Controller;
@AutoService(Instrumenter.class)
public final class SpringWebInstrumentation extends Instrumenter.Default {
public final class HandlerAdapterInstrumentation extends Instrumenter.Default {
public SpringWebInstrumentation() {
public HandlerAdapterInstrumentation() {
super("spring-web");
}
@ -55,15 +54,13 @@ public final class SpringWebInstrumentation extends Instrumenter.Default {
@Override
public Map<ElementMatcher, String> transformers() {
final Map<ElementMatcher, String> transformers = new HashMap<>();
transformers.put(
return Collections.<ElementMatcher, String>singletonMap(
isMethod()
.and(isPublic())
.and(nameStartsWith("handle"))
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest")))
.and(takesArguments(3)),
ControllerAdvice.class.getName());
return transformers;
}
public static class ControllerAdvice {