Refactor Ratpack

Remove the use of the OT project and Execution managed scopes. Updated tests.
This commit is contained in:
Gary 2018-11-09 02:42:49 -05:00 committed by Gary Huang
parent cf033baf7e
commit 6475f20308
No known key found for this signature in database
GPG Key ID: 0CB168EE6C6844B7
7 changed files with 310 additions and 137 deletions

View File

@ -51,7 +51,6 @@ testSets {
dependencies { dependencies {
main_java8CompileOnly group: 'io.ratpack', name: 'ratpack-core', version: '1.4.0' main_java8CompileOnly group: 'io.ratpack', name: 'ratpack-core', version: '1.4.0'
main_java8Compile project(':dd-trace-ot')
main_java8Compile project(':dd-java-agent:agent-tooling') main_java8Compile project(':dd-java-agent:agent-tooling')
main_java8Compile deps.bytebuddy main_java8Compile deps.bytebuddy
@ -65,6 +64,7 @@ dependencies {
compile sourceSets.main_java8.output compile sourceSets.main_java8.output
testCompile project(':dd-java-agent:testing') testCompile project(':dd-java-agent:testing')
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
testCompile group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.4.0' testCompile group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.4.0'
latestDepTestCompile group: 'io.ratpack', name: 'ratpack-groovy-test', version: '+' latestDepTestCompile group: 'io.ratpack', name: 'ratpack-groovy-test', version: '+'
} }

View File

@ -55,9 +55,6 @@ public final class RatpackHttpClientInstrumentation extends Instrumenter.Default
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$StreamedResponseAction", "datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$StreamedResponseAction",
"datadog.trace.instrumentation.ratpack.impl.RequestSpecInjectAdapter", "datadog.trace.instrumentation.ratpack.impl.RequestSpecInjectAdapter",
"datadog.trace.instrumentation.ratpack.impl.WrappedRequestSpec", "datadog.trace.instrumentation.ratpack.impl.WrappedRequestSpec",
// core helpers
"datadog.opentracing.scopemanager.ContextualScopeManager",
"datadog.opentracing.scopemanager.ScopeContext"
}; };
} }

View File

@ -55,13 +55,8 @@ public final class RatpackInstrumentation extends Instrumenter.Default {
@Override @Override
public String[] helperClassNames() { public String[] helperClassNames() {
return new String[] { return new String[] {
// core helpers
"datadog.opentracing.scopemanager.ContextualScopeManager",
"datadog.opentracing.scopemanager.ScopeContext",
// service registry helpers // service registry helpers
"datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter", "datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter",
"datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager",
"datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager$RatpackScope",
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice", "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice",
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice", "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice",
"datadog.trace.instrumentation.ratpack.impl.TracingHandler" "datadog.trace.instrumentation.ratpack.impl.TracingHandler"
@ -102,9 +97,6 @@ public final class RatpackInstrumentation extends Instrumenter.Default {
@Override @Override
public String[] helperClassNames() { public String[] helperClassNames() {
return new String[] { return new String[] {
// core helpers
"datadog.opentracing.scopemanager.ContextualScopeManager",
"datadog.opentracing.scopemanager.ScopeContext",
// exec helpers // exec helpers
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice", "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice",
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction" "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction"

View File

@ -1,82 +0,0 @@
package datadog.trace.instrumentation.ratpack.impl;
import datadog.opentracing.scopemanager.ScopeContext;
import io.opentracing.Scope;
import io.opentracing.Span;
import ratpack.exec.Execution;
import ratpack.exec.UnmanagedThreadException;
/**
* This scope manager uses the Ratpack Execution to store the current Scope. This is a ratpack
* registry analogous to a ThreadLocal but for an execution that may transfer between several
* threads
*/
public final class RatpackScopeManager implements ScopeContext {
@Override
public boolean inContext() {
return Execution.isManagedThread();
}
@Override
public Scope activate(Span span, boolean finishSpanOnClose) {
Execution execution = Execution.current();
RatpackScope ratpackScope =
new RatpackScope(
span, finishSpanOnClose, execution.maybeGet(RatpackScope.class).orElse(null));
// remove any existing RatpackScopes before adding it to the registry
execution
.maybeGet(RatpackScope.class)
.ifPresent(ignored -> execution.remove(RatpackScope.class));
execution.add(RatpackScope.class, ratpackScope);
execution.onComplete(
ratpackScope); // ensure that the scope is closed when the execution finishes
return ratpackScope;
}
@Override
public Scope active() {
try {
return Execution.current().maybeGet(RatpackScope.class).orElse(null);
} catch (UnmanagedThreadException ume) {
return null; // should never happen due to inContextCheck
}
}
static class RatpackScope implements Scope {
private final Span wrapped;
private final boolean finishOnClose;
private final RatpackScope toRestore;
RatpackScope(Span wrapped, boolean finishOnClose, RatpackScope toRestore) {
this.wrapped = wrapped;
this.finishOnClose = finishOnClose;
this.toRestore = toRestore;
}
@Override
public Span span() {
return wrapped;
}
@Override
public void close() {
Execution execution = Execution.current();
// only close if this scope is the current scope for this Execution
// As with ThreadLocalScope this shouldn't happen if users call methods in the expected order
execution
.maybeGet(RatpackScope.class)
.filter(s -> this == s)
.ifPresent(
ignore -> {
if (finishOnClose) {
wrapped.finish();
}
// pop the execution "stack"
execution.remove(RatpackScope.class);
if (toRestore != null) {
execution.add(toRestore);
}
});
}
}
}

View File

@ -1,6 +1,5 @@
package datadog.trace.instrumentation.ratpack.impl; package datadog.trace.instrumentation.ratpack.impl;
import datadog.opentracing.scopemanager.ContextualScopeManager;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.ScopeManager; import io.opentracing.ScopeManager;
import io.opentracing.util.GlobalTracer; import io.opentracing.util.GlobalTracer;
@ -17,25 +16,12 @@ public class RatpackServerAdvice {
public static class RatpackServerRegistryAdvice { public static class RatpackServerRegistryAdvice {
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void injectTracing(@Advice.Return(readOnly = false) Registry registry) { public static void injectTracing(@Advice.Return(readOnly = false) Registry registry) {
RatpackScopeManager ratpackScopeManager = new RatpackScopeManager();
// the value returned from ServerRegistry.buildBaseRegistry needs to be modified to add our
// scope manager and handler decorator to the registry
//noinspection UnusedAssignment
registry = registry =
registry.join( registry.join(
Registry.builder() Registry.builder()
.add(ScopeManager.class, ratpackScopeManager) .add(ScopeManager.class, GlobalTracer.get().scopeManager())
.add(HandlerDecorator.prepend(new TracingHandler())) .add(HandlerDecorator.prepend(new TracingHandler()))
.build()); .build());
if (GlobalTracer.isRegistered()) {
if (GlobalTracer.get().scopeManager() instanceof ContextualScopeManager) {
((ContextualScopeManager) GlobalTracer.get().scopeManager())
.addScopeContext(ratpackScopeManager);
}
} else {
log.warn("No GlobalTracer registered");
}
} }
} }
@ -43,9 +29,8 @@ public class RatpackServerAdvice {
@Advice.OnMethodEnter @Advice.OnMethodEnter
public static void addScopeToRegistry( public static void addScopeToRegistry(
@Advice.Argument(value = 0, readOnly = false) Action<? super RegistrySpec> action) { @Advice.Argument(value = 0, readOnly = false) Action<? super RegistrySpec> action) {
Scope active = GlobalTracer.get().scopeManager().active(); final Scope active = GlobalTracer.get().scopeManager().active();
if (active != null) { if (active != null) {
//noinspection UnusedAssignment
action = new ExecStarterAction(active).append(action); action = new ExecStarterAction(active).append(action);
} }
} }
@ -53,8 +38,8 @@ public class RatpackServerAdvice {
public static class ExecutionAdvice { public static class ExecutionAdvice {
@Advice.OnMethodExit @Advice.OnMethodExit
public static void addScopeToRegistry(@Advice.Return ExecStarter starter) { public static void addScopeToRegistry(@Advice.Return final ExecStarter starter) {
Scope active = GlobalTracer.get().scopeManager().active(); final Scope active = GlobalTracer.get().scopeManager().active();
if (active != null) { if (active != null) {
starter.register(new ExecStarterAction(active)); starter.register(new ExecStarterAction(active));
} }
@ -64,13 +49,12 @@ public class RatpackServerAdvice {
public static class ExecStarterAction implements Action<RegistrySpec> { public static class ExecStarterAction implements Action<RegistrySpec> {
private final Scope active; private final Scope active;
@SuppressWarnings("WeakerAccess") public ExecStarterAction(final Scope active) {
public ExecStarterAction(Scope active) {
this.active = active; this.active = active;
} }
@Override @Override
public void execute(RegistrySpec spec) { public void execute(final RegistrySpec spec) {
if (active != null) { if (active != null) {
spec.add(active); spec.add(active);
} }

View File

@ -2,6 +2,7 @@ package datadog.trace.instrumentation.ratpack.impl;
import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags; import datadog.trace.api.DDTags;
import datadog.trace.context.TraceScope;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Span; import io.opentracing.Span;
import io.opentracing.SpanContext; import io.opentracing.SpanContext;
@ -37,9 +38,16 @@ public final class TracingHandler implements Handler {
.withTag(Tags.HTTP_URL.getKey(), request.getUri()) .withTag(Tags.HTTP_URL.getKey(), request.getUri())
.startActive(true); .startActive(true);
if (scope instanceof TraceScope) {
((TraceScope) scope).setAsyncPropagation(true);
}
ctx.getResponse() ctx.getResponse()
.beforeSend( .beforeSend(
response -> { response -> {
if (scope instanceof TraceScope) {
((TraceScope) scope).setAsyncPropagation(false);
}
final Span span = scope.span(); final Span span = scope.span();
span.setTag(DDTags.RESOURCE_NAME, getResourceName(ctx)); span.setTag(DDTags.RESOURCE_NAME, getResourceName(ctx));
final Status status = response.getStatus(); final Status status = response.getStatus();
@ -49,6 +57,7 @@ public final class TracingHandler implements Handler {
} }
Tags.HTTP_STATUS.set(span, status.getCode()); Tags.HTTP_STATUS.set(span, status.getCode());
} }
scope.close(); scope.close();
}); });

View File

@ -1,9 +1,10 @@
import datadog.opentracing.scopemanager.ContextualScopeManager
import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.agent.test.utils.OkHttpUtils import datadog.trace.agent.test.utils.OkHttpUtils
import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDSpanTypes
import datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager import datadog.trace.api.DDTags
import datadog.trace.context.TraceScope
import io.opentracing.Scope import io.opentracing.Scope
import io.opentracing.tag.Tags
import io.opentracing.util.GlobalTracer import io.opentracing.util.GlobalTracer
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -37,12 +38,15 @@ class RatpackTest extends AgentTestRunner {
.url(app.address.toURL()) .url(app.address.toURL())
.get() .get()
.build() .build()
when: when:
def resp = client.newCall(request).execute() def resp = client.newCall(request).execute()
then: then:
resp.code() == 200 resp.code() == 200
resp.body.string() == "success" resp.body.string() == "success"
<<<<<<< HEAD
TEST_WRITER.size() == 1 TEST_WRITER.size() == 1
def trace = TEST_WRITER.firstTrace() def trace = TEST_WRITER.firstTrace()
trace.size() == 1 trace.size() == 1
@ -60,6 +64,29 @@ class RatpackTest extends AgentTestRunner {
span.context().tags["http.status_code"] == 200 span.context().tags["http.status_code"] == 200
span.context().tags["thread.name"] != null span.context().tags["thread.name"] != null
span.context().tags["thread.id"] != null span.context().tags["thread.id"] != null
=======
assertTraces(1) {
trace(0, 1) {
span(0) {
resourceName "GET /"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
parent()
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/"
defaultTags()
}
}
}
}
>>>>>>> 1bfa7e47... Refactor Ratpack
} }
def "test path with bindings call"() { def "test path with bindings call"() {
@ -77,12 +104,15 @@ class RatpackTest extends AgentTestRunner {
.url(HttpUrl.get(app.address).newBuilder().addPathSegments("a/b/baz").build()) .url(HttpUrl.get(app.address).newBuilder().addPathSegments("a/b/baz").build())
.get() .get()
.build() .build()
when: when:
def resp = client.newCall(request).execute() def resp = client.newCall(request).execute()
then: then:
resp.code() == 200 resp.code() == 200
resp.body.string() == ":foo/:bar?/baz" resp.body.string() == ":foo/:bar?/baz"
<<<<<<< HEAD
TEST_WRITER.size() == 1 TEST_WRITER.size() == 1
def trace = TEST_WRITER.firstTrace() def trace = TEST_WRITER.firstTrace()
trace.size() == 1 trace.size() == 1
@ -100,6 +130,29 @@ class RatpackTest extends AgentTestRunner {
span.context().tags["http.status_code"] == 200 span.context().tags["http.status_code"] == 200
span.context().tags["thread.name"] != null span.context().tags["thread.name"] != null
span.context().tags["thread.id"] != null span.context().tags["thread.id"] != null
=======
assertTraces(1) {
trace(0, 1) {
span(0) {
resourceName "GET /:foo/:bar?/baz"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
parent()
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/a/b/baz"
defaultTags()
}
}
}
}
>>>>>>> 1bfa7e47... Refactor Ratpack
} }
def "test error response"() { def "test error response"() {
@ -107,7 +160,9 @@ class RatpackTest extends AgentTestRunner {
def app = GroovyEmbeddedApp.ratpack { def app = GroovyEmbeddedApp.ratpack {
handlers { handlers {
get { get {
context.clientError(500) context.render(Promise.sync {
return "fail " + 0 / 0
})
} }
} }
} }
@ -120,6 +175,7 @@ class RatpackTest extends AgentTestRunner {
then: then:
resp.code() == 500 resp.code() == 500
<<<<<<< HEAD
TEST_WRITER.size() == 1 TEST_WRITER.size() == 1
def trace = TEST_WRITER.firstTrace() def trace = TEST_WRITER.firstTrace()
trace.size() == 1 trace.size() == 1
@ -137,6 +193,31 @@ class RatpackTest extends AgentTestRunner {
span.context().tags["http.status_code"] == 500 span.context().tags["http.status_code"] == 500
span.context().tags["thread.name"] != null span.context().tags["thread.name"] != null
span.context().tags["thread.id"] != null span.context().tags["thread.id"] != null
=======
assertTraces(1) {
trace(0, 1) {
span(0) {
resourceName "GET /"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
parent()
errored true
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 500
"$Tags.HTTP_URL.key" "/"
"error" true
// errorTags(Exception, String) // TODO: find out how to get throwable in instrumentation
defaultTags()
}
}
}
}
>>>>>>> 1bfa7e47... Refactor Ratpack
} }
def "test path call using ratpack http client"() { def "test path call using ratpack http client"() {
@ -173,8 +254,10 @@ class RatpackTest extends AgentTestRunner {
.url(app.address.toURL()) .url(app.address.toURL())
.get() .get()
.build() .build()
when: when:
def resp = client.newCall(request).execute() def resp = client.newCall(request).execute()
then: then:
resp.code() == 200 resp.code() == 200
resp.body().string() == "success" resp.body().string() == "success"
@ -182,6 +265,7 @@ class RatpackTest extends AgentTestRunner {
// 3rd is the three traces, ratpack, http client 2 and http client 1 // 3rd is the three traces, ratpack, http client 2 and http client 1
// 2nd is nested2 from the external server (the result of the 2nd internal http client call) // 2nd is nested2 from the external server (the result of the 2nd internal http client call)
// 1st is nested from the external server (the result of the 1st internal http client call) // 1st is nested from the external server (the result of the 1st internal http client call)
<<<<<<< HEAD
TEST_WRITER.size() == 3 TEST_WRITER.size() == 3
def trace = TEST_WRITER.get(2) def trace = TEST_WRITER.get(2)
trace.size() == 3 trace.size() == 3
@ -212,9 +296,121 @@ class RatpackTest extends AgentTestRunner {
clientTrace1.context().tags["http.status_code"] == 200 clientTrace1.context().tags["http.status_code"] == 200
clientTrace1.context().tags["thread.name"] != null clientTrace1.context().tags["thread.name"] != null
clientTrace1.context().tags["thread.id"] != null clientTrace1.context().tags["thread.id"] != null
=======
assertTraces(3) {
// simulated external system, first call
trace(0, 1) {
span(0) {
resourceName "GET /nested"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
childOf(trace(2).get(2))
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/nested"
defaultTags(true)
}
}
}
// simulated external system, second call
trace(1, 1) {
span(0) {
resourceName "GET /nested2"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
childOf(trace(2).get(1))
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/nested2"
defaultTags(true)
}
}
}
trace(2, 3) {
// main app span that processed the request from OKHTTP request
span(0) {
resourceName "GET /"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
parent()
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/"
defaultTags()
}
}
// Second http client call that receives the 'ess' of Success
span(1) {
resourceName "GET /?"
serviceName "unnamed-java-app"
operationName "ratpack.client-request"
spanType DDSpanTypes.HTTP_CLIENT
childOf(span(0))
errored false
tags {
"$Tags.COMPONENT.key" "httpclient"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "${external.address}nested2"
defaultTags()
}
}
// First http client call that receives the 'Succ' of Success
span(2) {
resourceName "GET /nested"
serviceName "unnamed-java-app"
operationName "ratpack.client-request"
spanType DDSpanTypes.HTTP_CLIENT
childOf(span(0))
errored false
tags {
"$Tags.COMPONENT.key" "httpclient"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "${external.address}nested"
defaultTags()
}
}
}
}
}
def clientTrace2 = trace[2] // First http client call that receives the 'Succ' of Success def "test forked path call and start span in handler (#startSpanInHandler)"() {
setup:
def app = GroovyEmbeddedApp.ratpack {
handlers {
get {
>>>>>>> 1bfa7e47... Refactor Ratpack
final Scope scope = !startSpanInHandler ? GlobalTracer.get().scopeManager().active() :
GlobalTracer.get()
.buildSpan("ratpack.exec-test")
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
.startActive(true)
<<<<<<< HEAD
clientTrace2.context().serviceName == "unnamed-java-app" clientTrace2.context().serviceName == "unnamed-java-app"
clientTrace2.context().operationName == "ratpack.client-request" clientTrace2.context().operationName == "ratpack.client-request"
clientTrace1.context().tags["component"] == "ratpack-httpclient" clientTrace1.context().tags["component"] == "ratpack-httpclient"
@ -225,11 +421,23 @@ class RatpackTest extends AgentTestRunner {
clientTrace2.context().tags["http.status_code"] == 200 clientTrace2.context().tags["http.status_code"] == 200
clientTrace2.context().tags["thread.name"] != null clientTrace2.context().tags["thread.name"] != null
clientTrace2.context().tags["thread.id"] != null clientTrace2.context().tags["thread.id"] != null
=======
((TraceScope) scope).setAsyncPropagation(true)
scope.span().setBaggageItem("test-baggage", "foo")
context.render(testPromise(startSpanInHandler).fork())
}
}
}
def request = new Request.Builder()
.url(app.address.toURL())
.get()
.build()
>>>>>>> 1bfa7e47... Refactor Ratpack
def nestedTrace = TEST_WRITER.get(1) when:
nestedTrace.size() == 1 def resp = client.newCall(request).execute()
def nestedSpan = nestedTrace[0] // simulated external system, second call
<<<<<<< HEAD
nestedSpan.context().serviceName == "unnamed-java-app" nestedSpan.context().serviceName == "unnamed-java-app"
nestedSpan.context().operationName == "ratpack.handler" nestedSpan.context().operationName == "ratpack.handler"
nestedSpan.context().resourceName == "GET /nested2" nestedSpan.context().resourceName == "GET /nested2"
@ -242,11 +450,49 @@ class RatpackTest extends AgentTestRunner {
nestedSpan.context().tags["http.status_code"] == 200 nestedSpan.context().tags["http.status_code"] == 200
nestedSpan.context().tags["thread.name"] != null nestedSpan.context().tags["thread.name"] != null
nestedSpan.context().tags["thread.id"] != null nestedSpan.context().tags["thread.id"] != null
=======
then:
resp.code() == 200
resp.body().string() == "foo"
>>>>>>> 1bfa7e47... Refactor Ratpack
def nestedTrace2 = TEST_WRITER.get(0) assertTraces(1) {
nestedTrace2.size() == 1 trace(0, (startSpanInHandler ? 2 : 1)) {
def nestedSpan2 = nestedTrace2[0] // simulated external system, first call span(0) {
resourceName "GET /"
serviceName "unnamed-java-app"
operationName "ratpack.handler"
spanType DDSpanTypes.HTTP_SERVER
parent()
errored false
tags {
"$Tags.COMPONENT.key" "handler"
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.HTTP_STATUS.key" 200
"$Tags.HTTP_URL.key" "/"
defaultTags()
}
}
if (startSpanInHandler) {
span(1) {
resourceName "INSIDE-TEST"
serviceName "unnamed-java-app"
operationName "ratpack.exec-test"
spanType DDSpanTypes.HTTP_SERVER
childOf(span(0))
errored false
tags {
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_SERVER
defaultTags()
}
}
}
}
}
<<<<<<< HEAD
nestedSpan2.context().serviceName == "unnamed-java-app" nestedSpan2.context().serviceName == "unnamed-java-app"
nestedSpan2.context().operationName == "ratpack.handler" nestedSpan2.context().operationName == "ratpack.handler"
nestedSpan2.context().resourceName == "GET /nested" nestedSpan2.context().resourceName == "GET /nested"
@ -259,33 +505,60 @@ class RatpackTest extends AgentTestRunner {
nestedSpan2.context().tags["http.status_code"] == 200 nestedSpan2.context().tags["http.status_code"] == 200
nestedSpan2.context().tags["thread.name"] != null nestedSpan2.context().tags["thread.name"] != null
nestedSpan2.context().tags["thread.id"] != null nestedSpan2.context().tags["thread.id"] != null
=======
where:
startSpanInHandler << [true, false]
>>>>>>> 1bfa7e47... Refactor Ratpack
} }
def "forked executions inherit parent scope"() { def "forked executions inherit parent scope"() {
when: when:
def result = ExecHarness.yieldSingle({ spec -> def result = ExecHarness.yieldSingle({}, {
// This does the work of the initial instrumentation that occurs on the server registry. Because we are using
// ExecHarness for testing this does not get executed by the instrumentation
def ratpackScopeManager = new RatpackScopeManager()
spec.add(ratpackScopeManager)
((ContextualScopeManager) GlobalTracer.get().scopeManager())
.addScopeContext(ratpackScopeManager)
}, {
final Scope scope = final Scope scope =
GlobalTracer.get() GlobalTracer.get()
.buildSpan("ratpack.exec-test") .buildSpan("ratpack.exec-test")
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
.startActive(true) .startActive(true)
((TraceScope) scope).setAsyncPropagation(true)
scope.span().setBaggageItem("test-baggage", "foo") scope.span().setBaggageItem("test-baggage", "foo")
ParallelBatch.of(testPromise(), testPromise()).yield() ParallelBatch.of(testPromise(false), testPromise(false))
.yield()
.map({ now ->
// close the scope now that we got the baggage inside the promises
scope.close()
return now
})
}) })
then: then:
result.valueOrThrow == ["foo", "foo"] result.valueOrThrow == ["foo", "foo"]
assertTraces(1) {
trace(0, 1) {
span(0) {
resourceName "INSIDE-TEST"
serviceName "unnamed-java-app"
operationName "ratpack.exec-test"
parent()
errored false
tags {
defaultTags()
}
}
}
}
} }
Promise<String> testPromise() { // returns a promise that contains the active scope's "test-baggage" baggage
// will close an active scope if closeSpan is set to true
Promise<String> testPromise(boolean closeSpan = true) {
Promise.sync { Promise.sync {
GlobalTracer.get().activeSpan().getBaggageItem("test-baggage") Scope tracerScope = GlobalTracer.get().scopeManager().active()
String res = tracerScope.span().getBaggageItem("test-baggage")
if (closeSpan) {
tracerScope.close()
}
return res
} }
} }
} }