From 14846a79df411ca8832b5c9569f33749ffef90da Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Wed, 3 Oct 2018 11:32:04 -0400 Subject: [PATCH] Add Dropwizard-views instrumentation --- .../dropwizard-views/dropwizard-views.gradle | 25 ++++++ .../view/DropwizardViewInstrumentation.java | 82 +++++++++++++++++++ .../src/test/groovy/ViewRenderTest.groovy | 46 +++++++++++ .../src/test/resources/views/ftl/iso88591.ftl | 10 +++ .../src/test/resources/views/ftl/utf8.ftl | 9 ++ .../views/mustache/iso88591.mustache | 10 +++ .../resources/views/mustache/utf8.mustache | 9 ++ .../dropwizard/dropwizard.gradle | 1 + settings.gradle | 2 + 9 files changed, 194 insertions(+) create mode 100644 dd-java-agent/instrumentation/dropwizard/dropwizard-views/dropwizard-views.gradle create mode 100644 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java create mode 100644 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/groovy/ViewRenderTest.groovy create mode 100755 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/iso88591.ftl create mode 100755 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/utf8.ftl create mode 100755 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/iso88591.mustache create mode 100755 dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/utf8.mustache create mode 100644 dd-java-agent/instrumentation/dropwizard/dropwizard.gradle diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/dropwizard-views.gradle b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/dropwizard-views.gradle new file mode 100644 index 0000000000..475c302930 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/dropwizard-views.gradle @@ -0,0 +1,25 @@ +muzzle { + pass { + group = 'io.dropwizard' + module = 'dropwizard-views' + versions = "(,)" + } +} + +apply from: "${rootDir}/gradle/java.gradle" + +dependencies { + compileOnly group: 'io.dropwizard', name: 'dropwizard-views', version: '0.7.0' + + compile project(':dd-java-agent:agent-tooling') + + compile deps.bytebuddy + compile deps.opentracing + annotationProcessor deps.autoservice + implementation deps.autoservice + + testCompile project(':dd-java-agent:testing') + + testCompile group: 'io.dropwizard', name: 'dropwizard-views-freemarker', version: '0.7.0' + testCompile group: 'io.dropwizard', name: 'dropwizard-views-mustache', version: '0.7.0' +} diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java new file mode 100644 index 0000000000..0a5b4eba85 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java @@ -0,0 +1,82 @@ +package datadog.trace.instrumentation.dropwizard.view; + +import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +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.isPublic; +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 datadog.trace.api.DDSpanTypes; +import datadog.trace.api.DDTags; +import io.dropwizard.views.View; +import io.opentracing.Scope; +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 net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public final class DropwizardViewInstrumentation extends Instrumenter.Default { + + public DropwizardViewInstrumentation() { + super("dropwizard", "dropwizard-view"); + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(safeHasSuperType(named("io.dropwizard.views.ViewRenderer"))); + } + + @Override + public Map transformers() { + final Map transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("render")) + .and(takesArgument(0, named("io.dropwizard.views.View"))) + .and(isPublic()), + RenderAdvice.class.getName()); + return transformers; + } + + public static class RenderAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Scope startSpan( + @Advice.This final Object obj, @Advice.Argument(0) final View view) { + final Scope scope = + GlobalTracer.get() + .buildSpan("view.render") + .withTag(DDTags.RESOURCE_NAME, "View " + view.getTemplateName()) + .withTag(Tags.COMPONENT.getKey(), "dropwizard-view") + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) + .withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_SERVER) + .withTag("span.origin.type", obj.getClass().getSimpleName()) + .startActive(true); + + return scope; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) { + + final Span span = scope.span(); + if (throwable != null) { + Tags.ERROR.set(span, Boolean.TRUE); + span.log(Collections.singletonMap(ERROR_OBJECT, throwable)); + } + scope.close(); + } + } +} diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/groovy/ViewRenderTest.groovy b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/groovy/ViewRenderTest.groovy new file mode 100644 index 0000000000..8299be19e7 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/groovy/ViewRenderTest.groovy @@ -0,0 +1,46 @@ +import datadog.trace.agent.test.AgentTestRunner +import io.dropwizard.views.View +import io.dropwizard.views.freemarker.FreemarkerViewRenderer +import io.dropwizard.views.mustache.MustacheViewRenderer + +import java.nio.charset.StandardCharsets + +import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces + +class ViewRenderTest extends AgentTestRunner { + + def "render #template succeeds with span"() { + setup: + def outputStream = new ByteArrayOutputStream() + + when: + renderer.render(view, Locale.ENGLISH, outputStream) + + then: + outputStream.toString().contains("This is an example of a view") + assertTraces(TEST_WRITER, 1) { + trace(0, 1) { + span(0) { + resourceName "View $template" + operationName "view.render" + tags { + "component" "dropwizard-view" + "span.origin.type" renderer.class.simpleName + "span.kind" "server" + "span.type" "web" + defaultTags() + } + } + } + } + + where: + renderer | template + new FreemarkerViewRenderer() | "/views/ftl/utf8.ftl" + new MustacheViewRenderer() | "/views/mustache/utf8.mustache" + new FreemarkerViewRenderer() | "/views/ftl/utf8.ftl" + new MustacheViewRenderer() | "/views/mustache/utf8.mustache" + + view = new View(template, StandardCharsets.UTF_8) {} + } +} diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/iso88591.ftl b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/iso88591.ftl new file mode 100755 index 0000000000..be7e5c9a75 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/iso88591.ftl @@ -0,0 +1,10 @@ + + + +

This is an example of a view containing ISO-8859-1 characters

+ +¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢ + + + + diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/utf8.ftl b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/utf8.ftl new file mode 100755 index 0000000000..86d499e6d1 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/ftl/utf8.ftl @@ -0,0 +1,9 @@ + + + +

This is an example of a view containing UTF-8 characters

+ +€€€€€€€€€€€€€€€€€€ + + + \ No newline at end of file diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/iso88591.mustache b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/iso88591.mustache new file mode 100755 index 0000000000..be7e5c9a75 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/iso88591.mustache @@ -0,0 +1,10 @@ + + + +

This is an example of a view containing ISO-8859-1 characters

+ +¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢ + + + + diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/utf8.mustache b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/utf8.mustache new file mode 100755 index 0000000000..86d499e6d1 --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/test/resources/views/mustache/utf8.mustache @@ -0,0 +1,9 @@ + + + +

This is an example of a view containing UTF-8 characters

+ +€€€€€€€€€€€€€€€€€€ + + + \ No newline at end of file diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard.gradle b/dd-java-agent/instrumentation/dropwizard/dropwizard.gradle new file mode 100644 index 0000000000..ff6901ae6f --- /dev/null +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard.gradle @@ -0,0 +1 @@ +apply from: "${rootDir}/gradle/java.gradle" diff --git a/settings.gradle b/settings.gradle index 1370f11b61..516e15ce86 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,8 @@ include ':dd-java-agent:instrumentation:aws-java-sdk-1.11.0' include ':dd-java-agent:instrumentation:aws-java-sdk-1.11.106' include ':dd-java-agent:instrumentation:couchbase-2.0' include ':dd-java-agent:instrumentation:datastax-cassandra-2.3' +include ':dd-java-agent:instrumentation:dropwizard' +include ':dd-java-agent:instrumentation:dropwizard:dropwizard-views' include ':dd-java-agent:instrumentation:elasticsearch-rest-5' include ':dd-java-agent:instrumentation:elasticsearch-transport-2' include ':dd-java-agent:instrumentation:elasticsearch-transport-5'