From 7ac2bdfc228f56a88d16000ed967a443fcec1e89 Mon Sep 17 00:00:00 2001 From: Andrew Kent Date: Mon, 11 Jun 2018 15:46:47 -0700 Subject: [PATCH] Add akka-http to play 2.6 tests --- .../src/lagomTest/groovy/LagomTest.groovy | 12 +- .../instrumentation/play-2.4/play-2.4.gradle | 1 + .../latestDepTest/groovy/Play26Test.groovy | 217 ++++++++++++------ .../play/PlayInstrumentation.java | 7 + 4 files changed, 168 insertions(+), 69 deletions(-) diff --git a/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/groovy/LagomTest.groovy b/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/groovy/LagomTest.groovy index afbf70a8ca..fa0a16324a 100644 --- a/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/groovy/LagomTest.groovy +++ b/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/groovy/LagomTest.groovy @@ -27,11 +27,13 @@ class LagomTest extends AgentTestRunner { @After @Override void afterTest() { - // FIXME: - // skipping error check - // bytebuddy is having trouble resolving akka.stream.impl.VirtualProcessor$WrappedSubscription$$SubscriptionState - // possibly due to '$$' in class name? - // class is on the classpath. + // 'akka/stream/impl/VirtualProcessor$WrappedSubscription$PassThrough$.class' declares + // itself an implementation of 'VirtualProcessor$WrappedSubscription$$SubscriptionState', + // but this interface does not exist on the classpath. + // The closest thing on the classpath is 'VirtualProcessor$WrappedSubscription$SubscriptionState' (only one $). + + // Looks like a compiler/packaging issue on akka's end. Or maybe this interface is dynamically generated. + // Either way, we're going to error out. } def setupSpec() { diff --git a/dd-java-agent/instrumentation/play-2.4/play-2.4.gradle b/dd-java-agent/instrumentation/play-2.4/play-2.4.gradle index fe3a04ee9c..7173c28208 100644 --- a/dd-java-agent/instrumentation/play-2.4/play-2.4.gradle +++ b/dd-java-agent/instrumentation/play-2.4/play-2.4.gradle @@ -23,6 +23,7 @@ dependencies { testCompile project(':dd-java-agent:testing') testCompile project(':dd-java-agent:instrumentation:java-concurrent') testCompile project(':dd-java-agent:instrumentation:trace-annotation') + testCompile project(':dd-java-agent:instrumentation:akka-http-10.0') testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0' latestDepTestCompile group: 'org.scala-lang', name: 'scala-library', version: '2.11.12' diff --git a/dd-java-agent/instrumentation/play-2.4/src/latestDepTest/groovy/Play26Test.groovy b/dd-java-agent/instrumentation/play-2.4/src/latestDepTest/groovy/Play26Test.groovy index 5c209a0abf..bb7df46988 100644 --- a/dd-java-agent/instrumentation/play-2.4/src/latestDepTest/groovy/Play26Test.groovy +++ b/dd-java-agent/instrumentation/play-2.4/src/latestDepTest/groovy/Play26Test.groovy @@ -1,4 +1,3 @@ -import datadog.opentracing.DDSpan import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.TestUtils import okhttp3.OkHttpClient @@ -7,7 +6,13 @@ import play.api.test.TestServer import play.test.Helpers import spock.lang.Shared +import static datadog.trace.agent.test.ListWriterAssert.assertTraces + class Play26Test extends AgentTestRunner { + static { + System.setProperty("dd.integration.akkahttp.enabled", "true") + } + @Shared int port = TestUtils.randomOpenPort() @Shared @@ -32,30 +37,49 @@ class Play26Test extends AgentTestRunner { .get() .build() def response = client.newCall(request).execute() - TEST_WRITER.waitForTraces(1) - DDSpan[] playTrace = TEST_WRITER.get(0) - DDSpan root = playTrace[0] expect: - testServer != null response.code() == 200 response.body().string() == "hello spock" - - // async work is linked to play trace - playTrace.size() == 2 - playTrace[1].operationName == 'TracedWork$.doWork' - - root.traceId == 123 - root.parentId == 456 - root.serviceName == "unnamed-java-app" - root.operationName == "play.request" - root.resourceName == "GET /helloplay/:from" - !root.context().getErrorFlag() - root.context().tags["http.status_code"] == 200 - root.context().tags["http.url"] == "/helloplay/:from" - root.context().tags["http.method"] == "GET" - root.context().tags["span.kind"] == "server" - root.context().tags["component"] == "play-action" + assertTraces(TEST_WRITER, 1) { + trace(0, 3) { + span(0) { + traceId 123 + parentId 456 + serviceName "unnamed-java-app" + operationName "akkahttp.request" + resourceName "GET /helloplay/:from" + errored false + tags { + defaultTags() + "http.status_code" 200 + "http.url" "http://localhost:$port/helloplay/spock" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "akkahttp-action" + } + } + span(1) { + childOf span(0) + operationName "play.request" + resourceName "GET /helloplay/:from" + tags { + defaultTags() + "http.status_code" 200 + "http.url" "/helloplay/:from" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "play-action" + } + } + span(2) { + childOf span(1) + operationName 'TracedWork$.doWork' + } + } + } } def "5xx errors trace" () { @@ -66,23 +90,45 @@ class Play26Test extends AgentTestRunner { .get() .build() def response = client.newCall(request).execute() - TEST_WRITER.waitForTraces(1) - DDSpan[] playTrace = TEST_WRITER.get(0) - DDSpan root = playTrace[0] expect: - testServer != null response.code() == 500 - - root.serviceName == "unnamed-java-app" - root.operationName == "play.request" - root.resourceName == "GET /make-error" - root.context().getErrorFlag() - root.context().tags["http.status_code"] == 500 - root.context().tags["http.url"] == "/make-error" - root.context().tags["http.method"] == "GET" - root.context().tags["span.kind"] == "server" - root.context().tags["component"] == "play-action" + assertTraces(TEST_WRITER, 1) { + trace(0, 2) { + span(0) { + serviceName "unnamed-java-app" + operationName "akkahttp.request" + resourceName "GET /make-error" + errored true + tags { + defaultTags() + "http.status_code" 500 + "http.url" "http://localhost:$port/make-error" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "akkahttp-action" + "error" true + } + } + span(1) { + childOf span(0) + operationName "play.request" + resourceName "GET /make-error" + errored true + tags { + defaultTags() + "http.status_code" 500 + "http.url" "/make-error" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "play-action" + "error" true + } + } + } + } } def "error thrown in request" () { @@ -93,26 +139,49 @@ class Play26Test extends AgentTestRunner { .get() .build() def response = client.newCall(request).execute() - TEST_WRITER.waitForTraces(1) - DDSpan[] playTrace = TEST_WRITER.get(0) - DDSpan root = playTrace[0] expect: testServer != null response.code() == 500 - - root.context().getErrorFlag() - root.context().tags["error.msg"] == "oh no" - root.context().tags["error.type"] == RuntimeException.getName() - - root.serviceName == "unnamed-java-app" - root.operationName == "play.request" - root.resourceName == "GET /exception" - root.context().tags["http.status_code"] == 500 - root.context().tags["http.url"] == "/exception" - root.context().tags["http.method"] == "GET" - root.context().tags["span.kind"] == "server" - root.context().tags["component"] == "play-action" + assertTraces(TEST_WRITER, 1) { + trace(0, 2) { + span(0) { + serviceName "unnamed-java-app" + operationName "akkahttp.request" + resourceName "GET /exception" + errored true + tags { + defaultTags() + "http.status_code" 500 + "http.url" "http://localhost:$port/exception" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "akkahttp-action" + "error" true + } + } + span(1) { + childOf span(0) + operationName "play.request" + resourceName "GET /exception" + errored true + tags { + defaultTags() + "http.status_code" 500 + "http.url" "/exception" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "play-action" + "error" true + "error.msg" "oh no" + "error.type" RuntimeException.getName() + "error.stack" tag("error.stack") + } + } + } + } } def "4xx errors trace" () { @@ -123,22 +192,42 @@ class Play26Test extends AgentTestRunner { .get() .build() def response = client.newCall(request).execute() - TEST_WRITER.waitForTraces(1) - DDSpan[] playTrace = TEST_WRITER.get(0) - DDSpan root = playTrace[0] expect: - testServer != null response.code() == 404 - root.serviceName == "unnamed-java-app" - root.operationName == "play.request" - root.resourceName == "404" - !root.context().getErrorFlag() - root.context().tags["http.status_code"] == 404 - root.context().tags["http.url"] == null - root.context().tags["http.method"] == "GET" - root.context().tags["span.kind"] == "server" - root.context().tags["component"] == "play-action" + assertTraces(TEST_WRITER, 1) { + trace(0, 2) { + span(0) { + serviceName "unnamed-java-app" + operationName "akkahttp.request" + resourceName "404" + errored false + tags { + defaultTags() + "http.status_code" 404 + "http.url" "http://localhost:$port/nowhere" + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "akkahttp-action" + } + } + span(1) { + childOf span(0) + operationName "play.request" + resourceName "404" + errored false + tags { + defaultTags() + "http.status_code" 404 + "http.method" "GET" + "span.kind" "server" + "span.type" "web" + "component" "play-action" + } + } + } + } } } diff --git a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java index 93acd519b6..04b858bfe3 100644 --- a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java +++ b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play/PlayInstrumentation.java @@ -130,6 +130,13 @@ public final class PlayInstrumentation extends Instrumenter.Configurable { scope.span().finish(); } scope.close(); + + final Span rootSpan = GlobalTracer.get().activeSpan(); + if (rootSpan != null && !pathOption.isEmpty()) { + // set the resource name on the upstream akka/netty span + final String path = (String) pathOption.get(); + rootSpan.setTag(DDTags.RESOURCE_NAME, req.method() + " " + path); + } } }