Merge pull request #797 from DataDog/tyler/ratpack
Update ratpack instrumentation and remove default disabled.
This commit is contained in:
commit
dc2e435de9
|
@ -32,10 +32,10 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
* <p>For now we're hardcoding this to the instrumentation package so we only create references
|
* <p>For now we're hardcoding this to the instrumentation package so we only create references
|
||||||
* from the method advice and helper classes.
|
* from the method advice and helper classes.
|
||||||
*/
|
*/
|
||||||
private static String REFERENCE_CREATION_PACKAGE = "datadog.trace.instrumentation.";
|
private static final String REFERENCE_CREATION_PACKAGE = "datadog.trace.instrumentation.";
|
||||||
|
|
||||||
public static Map<String, Reference> createReferencesFrom(
|
public static Map<String, Reference> createReferencesFrom(
|
||||||
String entryPointClassName, ClassLoader loader) {
|
final String entryPointClassName, final ClassLoader loader) {
|
||||||
return ReferenceCreator.createReferencesFrom(entryPointClassName, loader, true);
|
return ReferenceCreator.createReferencesFrom(entryPointClassName, loader, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,9 +46,11 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
* @param loader Classloader used to read class bytes.
|
* @param loader Classloader used to read class bytes.
|
||||||
* @param startFromMethodBodies if true only create refs from method bodies.
|
* @param startFromMethodBodies if true only create refs from method bodies.
|
||||||
* @return Map of [referenceClassName -> Reference]
|
* @return Map of [referenceClassName -> Reference]
|
||||||
|
* @throws IllegalStateException if class is not found or unable to be loaded.
|
||||||
*/
|
*/
|
||||||
private static Map<String, Reference> createReferencesFrom(
|
private static Map<String, Reference> createReferencesFrom(
|
||||||
String entryPointClassName, ClassLoader loader, boolean startFromMethodBodies) {
|
final String entryPointClassName, final ClassLoader loader, boolean startFromMethodBodies)
|
||||||
|
throws IllegalStateException {
|
||||||
final Set<String> visitedSources = new HashSet<>();
|
final Set<String> visitedSources = new HashSet<>();
|
||||||
final Map<String, Reference> references = new HashMap<>();
|
final Map<String, Reference> references = new HashMap<>();
|
||||||
|
|
||||||
|
@ -58,37 +60,38 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
while (!instrumentationQueue.isEmpty()) {
|
while (!instrumentationQueue.isEmpty()) {
|
||||||
final String className = instrumentationQueue.remove();
|
final String className = instrumentationQueue.remove();
|
||||||
visitedSources.add(className);
|
visitedSources.add(className);
|
||||||
|
final InputStream in = loader.getResourceAsStream(Utils.getResourceName(className));
|
||||||
try {
|
try {
|
||||||
final InputStream in = loader.getResourceAsStream(Utils.getResourceName(className));
|
final ReferenceCreator cv = new ReferenceCreator(null, startFromMethodBodies);
|
||||||
try {
|
// only start from method bodies on the first pass
|
||||||
final ReferenceCreator cv = new ReferenceCreator(null, startFromMethodBodies);
|
startFromMethodBodies = false;
|
||||||
// only start from method bodies on the first pass
|
final ClassReader reader = new ClassReader(in);
|
||||||
startFromMethodBodies = false;
|
reader.accept(cv, ClassReader.SKIP_FRAMES);
|
||||||
final ClassReader reader = new ClassReader(in);
|
|
||||||
reader.accept(cv, ClassReader.SKIP_FRAMES);
|
|
||||||
|
|
||||||
Map<String, Reference> instrumentationReferences = cv.getReferences();
|
final Map<String, Reference> instrumentationReferences = cv.getReferences();
|
||||||
for (Map.Entry<String, Reference> entry : instrumentationReferences.entrySet()) {
|
for (final Map.Entry<String, Reference> entry : instrumentationReferences.entrySet()) {
|
||||||
// Don't generate references created outside of the datadog instrumentation package.
|
// Don't generate references created outside of the datadog instrumentation package.
|
||||||
if (!visitedSources.contains(entry.getKey())
|
if (!visitedSources.contains(entry.getKey())
|
||||||
&& entry.getKey().startsWith(REFERENCE_CREATION_PACKAGE)) {
|
&& entry.getKey().startsWith(REFERENCE_CREATION_PACKAGE)) {
|
||||||
instrumentationQueue.add(entry.getKey());
|
instrumentationQueue.add(entry.getKey());
|
||||||
}
|
|
||||||
if (references.containsKey(entry.getKey())) {
|
|
||||||
references.put(
|
|
||||||
entry.getKey(), references.get(entry.getKey()).merge(entry.getValue()));
|
|
||||||
} else {
|
|
||||||
references.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (references.containsKey(entry.getKey())) {
|
||||||
} finally {
|
references.put(entry.getKey(), references.get(entry.getKey()).merge(entry.getValue()));
|
||||||
if (in != null) {
|
} else {
|
||||||
in.close();
|
references.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new IllegalStateException("Error reading class " + className, e);
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new IllegalStateException("Error closing class " + className, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new IllegalStateException(ioe);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return references;
|
return references;
|
||||||
|
@ -99,7 +102,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
*
|
*
|
||||||
* <p>foo/bar/Baz -> foo/bar/
|
* <p>foo/bar/Baz -> foo/bar/
|
||||||
*/
|
*/
|
||||||
private static String internalPackageName(String internalName) {
|
private static String internalPackageName(final String internalName) {
|
||||||
return internalName.replaceAll("/[^/]+$", "");
|
return internalName.replaceAll("/[^/]+$", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +111,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
*
|
*
|
||||||
* @return A reference flag with the required level of access.
|
* @return A reference flag with the required level of access.
|
||||||
*/
|
*/
|
||||||
private static Reference.Flag computeMinimumClassAccess(Type from, Type to) {
|
private static Reference.Flag computeMinimumClassAccess(final Type from, final Type to) {
|
||||||
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
||||||
return Reference.Flag.PRIVATE_OR_HIGHER;
|
return Reference.Flag.PRIVATE_OR_HIGHER;
|
||||||
} else if (internalPackageName(from.getInternalName())
|
} else if (internalPackageName(from.getInternalName())
|
||||||
|
@ -124,7 +127,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
*
|
*
|
||||||
* @return A reference flag with the required level of access.
|
* @return A reference flag with the required level of access.
|
||||||
*/
|
*/
|
||||||
private static Reference.Flag computeMinimumFieldAccess(Type from, Type to) {
|
private static Reference.Flag computeMinimumFieldAccess(final Type from, final Type to) {
|
||||||
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
||||||
return Reference.Flag.PRIVATE_OR_HIGHER;
|
return Reference.Flag.PRIVATE_OR_HIGHER;
|
||||||
} else if (internalPackageName(from.getInternalName())
|
} else if (internalPackageName(from.getInternalName())
|
||||||
|
@ -142,7 +145,8 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
*
|
*
|
||||||
* @return A reference flag with the required level of access.
|
* @return A reference flag with the required level of access.
|
||||||
*/
|
*/
|
||||||
private static Reference.Flag computeMinimumMethodAccess(Type from, Type to, Type methodType) {
|
private static Reference.Flag computeMinimumMethodAccess(
|
||||||
|
final Type from, final Type to, final Type methodType) {
|
||||||
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
if (from.getInternalName().equalsIgnoreCase(to.getInternalName())) {
|
||||||
return Reference.Flag.PRIVATE_OR_HIGHER;
|
return Reference.Flag.PRIVATE_OR_HIGHER;
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,12 +167,13 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Reference> references = new HashMap<>();
|
private final Map<String, Reference> references = new HashMap<>();
|
||||||
private String refSourceClassName;
|
private String refSourceClassName;
|
||||||
private Type refSourceType;
|
private Type refSourceType;
|
||||||
private boolean createFromMethodBodiesOnly;
|
private final boolean createFromMethodBodiesOnly;
|
||||||
|
|
||||||
private ReferenceCreator(ClassVisitor classVisitor, boolean createFromMethodBodiesOnly) {
|
private ReferenceCreator(
|
||||||
|
final ClassVisitor classVisitor, final boolean createFromMethodBodiesOnly) {
|
||||||
super(Opcodes.ASM7, classVisitor);
|
super(Opcodes.ASM7, classVisitor);
|
||||||
this.createFromMethodBodiesOnly = createFromMethodBodiesOnly;
|
this.createFromMethodBodiesOnly = createFromMethodBodiesOnly;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +182,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
return references;
|
return references;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addReference(Reference ref) {
|
private void addReference(final Reference ref) {
|
||||||
if (references.containsKey(ref.getClassName())) {
|
if (references.containsKey(ref.getClassName())) {
|
||||||
references.put(ref.getClassName(), references.get(ref.getClassName()).merge(ref));
|
references.put(ref.getClassName(), references.get(ref.getClassName()).merge(ref));
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,7 +208,11 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldVisitor visitField(
|
public FieldVisitor visitField(
|
||||||
int access, String name, String descriptor, String signature, Object value) {
|
final int access,
|
||||||
|
final String name,
|
||||||
|
final String descriptor,
|
||||||
|
final String signature,
|
||||||
|
final Object value) {
|
||||||
// Additional references we could check
|
// Additional references we could check
|
||||||
// - annotations on field
|
// - annotations on field
|
||||||
|
|
||||||
|
@ -228,7 +237,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
private class AdviceReferenceMethodVisitor extends MethodVisitor {
|
private class AdviceReferenceMethodVisitor extends MethodVisitor {
|
||||||
private int currentLineNumber = -1;
|
private int currentLineNumber = -1;
|
||||||
|
|
||||||
public AdviceReferenceMethodVisitor(MethodVisitor methodVisitor) {
|
public AdviceReferenceMethodVisitor(final MethodVisitor methodVisitor) {
|
||||||
super(Opcodes.ASM7, methodVisitor);
|
super(Opcodes.ASM7, methodVisitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +248,8 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
|
public void visitFieldInsn(
|
||||||
|
final int opcode, final String owner, final String name, final String descriptor) {
|
||||||
// Additional references we could check
|
// Additional references we could check
|
||||||
// * DONE owner class
|
// * DONE owner class
|
||||||
// * DONE owner class has a field (name)
|
// * DONE owner class has a field (name)
|
||||||
|
@ -253,7 +263,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
final Type ownerType = Type.getType("L" + owner + ";");
|
final Type ownerType = Type.getType("L" + owner + ";");
|
||||||
final Type fieldType = Type.getType(descriptor);
|
final Type fieldType = Type.getType(descriptor);
|
||||||
|
|
||||||
List<Reference.Flag> fieldFlags = new ArrayList<>();
|
final List<Reference.Flag> fieldFlags = new ArrayList<>();
|
||||||
fieldFlags.add(computeMinimumFieldAccess(refSourceType, ownerType));
|
fieldFlags.add(computeMinimumFieldAccess(refSourceType, ownerType));
|
||||||
fieldFlags.add(
|
fieldFlags.add(
|
||||||
opcode == Opcodes.GETSTATIC || opcode == Opcodes.PUTSTATIC
|
opcode == Opcodes.GETSTATIC || opcode == Opcodes.PUTSTATIC
|
||||||
|
@ -324,7 +334,7 @@ public class ReferenceCreator extends ClassVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type ownerType = Type.getType("L" + owner + ";");
|
final Type ownerType = Type.getType("L" + owner + ";");
|
||||||
|
|
||||||
final List<Reference.Flag> methodFlags = new ArrayList<>();
|
final List<Reference.Flag> methodFlags = new ArrayList<>();
|
||||||
methodFlags.add(
|
methodFlags.add(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package datadog.trace.instrumentation.netty40;
|
package datadog.trace.instrumentation.netty40;
|
||||||
|
|
||||||
import datadog.trace.context.TraceScope;
|
import datadog.trace.context.TraceScope;
|
||||||
|
import datadog.trace.instrumentation.netty40.client.HttpClientTracingHandler;
|
||||||
import datadog.trace.instrumentation.netty40.server.HttpServerTracingHandler;
|
import datadog.trace.instrumentation.netty40.server.HttpServerTracingHandler;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
|
@ -14,5 +15,5 @@ public class AttributeKeys {
|
||||||
new AttributeKey<>(HttpServerTracingHandler.class.getName() + ".span");
|
new AttributeKey<>(HttpServerTracingHandler.class.getName() + ".span");
|
||||||
|
|
||||||
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
|
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
|
||||||
new AttributeKey<>(HttpServerTracingHandler.class.getName() + ".span");
|
new AttributeKey<>(HttpClientTracingHandler.class.getName() + ".span");
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,14 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
|
||||||
return new String[] {
|
return new String[] {
|
||||||
packageName + ".AttributeKeys",
|
packageName + ".AttributeKeys",
|
||||||
"datadog.trace.agent.decorator.BaseDecorator",
|
"datadog.trace.agent.decorator.BaseDecorator",
|
||||||
|
// client helpers
|
||||||
|
"datadog.trace.agent.decorator.ClientDecorator",
|
||||||
|
"datadog.trace.agent.decorator.HttpClientDecorator",
|
||||||
|
packageName + ".client.NettyHttpClientDecorator",
|
||||||
|
packageName + ".client.NettyResponseInjectAdapter",
|
||||||
|
packageName + ".client.HttpClientRequestTracingHandler",
|
||||||
|
packageName + ".client.HttpClientResponseTracingHandler",
|
||||||
|
packageName + ".client.HttpClientTracingHandler",
|
||||||
// server helpers
|
// server helpers
|
||||||
"datadog.trace.agent.decorator.ServerDecorator",
|
"datadog.trace.agent.decorator.ServerDecorator",
|
||||||
"datadog.trace.agent.decorator.HttpServerDecorator",
|
"datadog.trace.agent.decorator.HttpServerDecorator",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package datadog.trace.instrumentation.netty41;
|
package datadog.trace.instrumentation.netty41;
|
||||||
|
|
||||||
import datadog.trace.context.TraceScope;
|
import datadog.trace.context.TraceScope;
|
||||||
|
import datadog.trace.instrumentation.netty41.client.HttpClientTracingHandler;
|
||||||
import datadog.trace.instrumentation.netty41.server.HttpServerTracingHandler;
|
import datadog.trace.instrumentation.netty41.server.HttpServerTracingHandler;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
|
@ -10,9 +11,13 @@ public class AttributeKeys {
|
||||||
PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY =
|
PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY =
|
||||||
AttributeKey.valueOf("datadog.trace.instrumentation.netty41.parent.connect.continuation");
|
AttributeKey.valueOf("datadog.trace.instrumentation.netty41.parent.connect.continuation");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constant is copied over to datadog.trace.instrumentation.ratpack.server.TracingHandler, so
|
||||||
|
* if this changes, that must also change.
|
||||||
|
*/
|
||||||
public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY =
|
public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY =
|
||||||
AttributeKey.valueOf(HttpServerTracingHandler.class.getName() + ".span");
|
AttributeKey.valueOf(HttpServerTracingHandler.class.getName() + ".span");
|
||||||
|
|
||||||
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
|
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
|
||||||
AttributeKey.valueOf(HttpServerTracingHandler.class.getName() + ".span");
|
AttributeKey.valueOf(HttpClientTracingHandler.class.getName() + ".span");
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,14 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
|
||||||
return new String[] {
|
return new String[] {
|
||||||
packageName + ".AttributeKeys",
|
packageName + ".AttributeKeys",
|
||||||
"datadog.trace.agent.decorator.BaseDecorator",
|
"datadog.trace.agent.decorator.BaseDecorator",
|
||||||
|
// client helpers
|
||||||
|
"datadog.trace.agent.decorator.ClientDecorator",
|
||||||
|
"datadog.trace.agent.decorator.HttpClientDecorator",
|
||||||
|
packageName + ".client.NettyHttpClientDecorator",
|
||||||
|
packageName + ".client.NettyResponseInjectAdapter",
|
||||||
|
packageName + ".client.HttpClientRequestTracingHandler",
|
||||||
|
packageName + ".client.HttpClientResponseTracingHandler",
|
||||||
|
packageName + ".client.HttpClientTracingHandler",
|
||||||
// server helpers
|
// server helpers
|
||||||
"datadog.trace.agent.decorator.ServerDecorator",
|
"datadog.trace.agent.decorator.ServerDecorator",
|
||||||
"datadog.trace.agent.decorator.HttpServerDecorator",
|
"datadog.trace.agent.decorator.HttpServerDecorator",
|
||||||
|
@ -102,7 +110,7 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void deactivateScope(@Advice.Enter final TraceScope scope) {
|
public static void deactivateScope(@Advice.Enter final TraceScope scope) {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
((Scope) scope).close();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ muzzle {
|
||||||
module = 'ratpack-core'
|
module = 'ratpack-core'
|
||||||
versions = "[1.4.0,)"
|
versions = "[1.4.0,)"
|
||||||
}
|
}
|
||||||
|
// Some maven dependencies are missing for pre 1.0 ratpack, so we can't assertInverse.
|
||||||
|
fail {
|
||||||
|
group = "io.ratpack"
|
||||||
|
module = 'ratpack-core'
|
||||||
|
versions = "[1.0,1.4.0)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "${rootDir}/gradle/java.gradle"
|
apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
@ -39,9 +45,7 @@ dependencies {
|
||||||
apply plugin: 'org.unbroken-dome.test-sets'
|
apply plugin: 'org.unbroken-dome.test-sets'
|
||||||
|
|
||||||
testSets {
|
testSets {
|
||||||
latestDepTest {
|
latestDepTest
|
||||||
dirName = 'test'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -61,6 +65,7 @@ dependencies {
|
||||||
|
|
||||||
testCompile project(':dd-java-agent:testing')
|
testCompile project(':dd-java-agent:testing')
|
||||||
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
|
testCompile project(':dd-java-agent:instrumentation:java-concurrent')
|
||||||
|
testCompile project(':dd-java-agent:instrumentation:netty-4.1')
|
||||||
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: '+'
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,702 @@
|
||||||
|
import datadog.trace.agent.test.AgentTestRunner
|
||||||
|
import datadog.trace.agent.test.utils.OkHttpUtils
|
||||||
|
import datadog.trace.api.DDSpanTypes
|
||||||
|
import datadog.trace.api.DDTags
|
||||||
|
import datadog.trace.context.TraceScope
|
||||||
|
import io.netty.channel.AbstractChannel
|
||||||
|
import io.opentracing.Scope
|
||||||
|
import io.opentracing.Span
|
||||||
|
import io.opentracing.tag.Tags
|
||||||
|
import io.opentracing.util.GlobalTracer
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import ratpack.exec.Promise
|
||||||
|
import ratpack.exec.util.ParallelBatch
|
||||||
|
import ratpack.groovy.test.embed.GroovyEmbeddedApp
|
||||||
|
import ratpack.handling.internal.HandlerException
|
||||||
|
import ratpack.http.HttpUrlBuilder
|
||||||
|
import ratpack.http.client.HttpClient
|
||||||
|
import ratpack.path.PathBinding
|
||||||
|
import ratpack.test.exec.ExecHarness
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
import static datadog.trace.agent.test.server.http.TestHttpServer.distributedRequestTrace
|
||||||
|
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
|
||||||
|
import static datadog.trace.agent.test.utils.PortUtils.UNUSABLE_PORT
|
||||||
|
|
||||||
|
class RatpackTest extends AgentTestRunner {
|
||||||
|
|
||||||
|
OkHttpClient client = OkHttpUtils.client()
|
||||||
|
|
||||||
|
def "test path call"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
context.render("success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 200
|
||||||
|
resp.body.string() == "success"
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test path with bindings call"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
prefix(":foo/:bar?") {
|
||||||
|
get("baz") { ctx ->
|
||||||
|
context.render(ctx.get(PathBinding).description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(HttpUrl.get(app.address).newBuilder().addPathSegments("a/b/baz").build())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 200
|
||||||
|
resp.body.string() == ":foo/:bar?/baz"
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /:foo/:bar?/baz"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "${app.address}a/b/baz"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /:foo/:bar?/baz"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "/a/b/baz"
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test handler error response"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
0 / 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
errorTags(HandlerException, Pattern.compile("java.lang.ArithmeticException: Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test promise error response"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
Promise.async {
|
||||||
|
0 / 0
|
||||||
|
}.then {
|
||||||
|
context.render(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test render error response"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
context.render(Promise.sync {
|
||||||
|
return "fail " + 0 / 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test path call using ratpack http client"() {
|
||||||
|
setup:
|
||||||
|
|
||||||
|
// Use jetty based server to avoid confusion.
|
||||||
|
def external = httpServer {
|
||||||
|
handlers {
|
||||||
|
get("nested") {
|
||||||
|
handleDistributedRequest()
|
||||||
|
response.send("succ")
|
||||||
|
}
|
||||||
|
get("nested2") {
|
||||||
|
handleDistributedRequest()
|
||||||
|
response.send("ess")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get { HttpClient httpClient ->
|
||||||
|
// 1st internal http client call to nested
|
||||||
|
httpClient.get(HttpUrlBuilder.base(external.address).path("nested").build())
|
||||||
|
.map { it.body.text }
|
||||||
|
.flatMap { t ->
|
||||||
|
// make a 2nd http request and concatenate the two bodies together
|
||||||
|
httpClient.get(HttpUrlBuilder.base(external.address).path("nested2").build()) map { t + it.body.text }
|
||||||
|
}
|
||||||
|
.then {
|
||||||
|
context.render(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 200
|
||||||
|
resp.body().string() == "success"
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// 1st is nested from the external server (the result of the 1st internal http client call)
|
||||||
|
assertTraces(3) {
|
||||||
|
distributedRequestTrace(it, 0, trace(2).get(3))
|
||||||
|
distributedRequestTrace(it, 1, trace(2).get(2))
|
||||||
|
|
||||||
|
trace(2, 4) {
|
||||||
|
// main app span that processed the request from OKHTTP request
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_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(2) {
|
||||||
|
resourceName "GET /?"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.client.request"
|
||||||
|
spanType DDSpanTypes.HTTP_CLIENT
|
||||||
|
childOf(span(3))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty-client"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "${external.address}/nested2"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// First http client call that receives the 'Succ' of Success
|
||||||
|
span(3) {
|
||||||
|
resourceName "GET /nested"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.client.request"
|
||||||
|
spanType DDSpanTypes.HTTP_CLIENT
|
||||||
|
childOf(span(1))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty-client"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "${external.address}/nested"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test ratpack http client error handling"() {
|
||||||
|
setup:
|
||||||
|
def badAddress = new URI("http://localhost:$UNUSABLE_PORT")
|
||||||
|
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get { HttpClient httpClient ->
|
||||||
|
httpClient.get(badAddress)
|
||||||
|
.map { it.body.text }
|
||||||
|
.then {
|
||||||
|
context.render(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 3) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(2) {
|
||||||
|
operationName "netty.connect"
|
||||||
|
resourceName "netty.connect"
|
||||||
|
childOf(span(1))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
errorTags(AbstractChannel.AnnotatedConnectException, String)
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test forked path call and start span in handler (#startSpanInHandler)"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
TraceScope scope
|
||||||
|
if (startSpanInHandler) {
|
||||||
|
Span childSpan = GlobalTracer.get()
|
||||||
|
.buildSpan("ratpack.exec-test")
|
||||||
|
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
|
||||||
|
.start()
|
||||||
|
scope = GlobalTracer.get().scopeManager().activate(childSpan, true)
|
||||||
|
}
|
||||||
|
def latch = new CountDownLatch(1)
|
||||||
|
try {
|
||||||
|
scope?.setAsyncPropagation(true)
|
||||||
|
GlobalTracer.get().activeSpan().setBaggageItem("test-baggage", "foo")
|
||||||
|
|
||||||
|
context.render(testPromise(latch).fork())
|
||||||
|
} finally {
|
||||||
|
scope?.close()
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 200
|
||||||
|
resp.body().string() == "foo"
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, (startSpanInHandler ? 3 : 2)) {
|
||||||
|
if (startSpanInHandler) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "INSIDE-TEST"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.exec-test"
|
||||||
|
childOf(span(2))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(startSpanInHandler ? 1 : 0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(startSpanInHandler ? 2 : 1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(startSpanInHandler ? 1 : 0))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
where:
|
||||||
|
startSpanInHandler << [true, false]
|
||||||
|
}
|
||||||
|
|
||||||
|
def "forked executions inherit parent scope"() {
|
||||||
|
when:
|
||||||
|
def result = ExecHarness.yieldSingle({}, {
|
||||||
|
final Scope scope =
|
||||||
|
GlobalTracer.get()
|
||||||
|
.buildSpan("ratpack.exec-test")
|
||||||
|
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
|
||||||
|
.startActive(true)
|
||||||
|
|
||||||
|
((TraceScope) scope).setAsyncPropagation(true)
|
||||||
|
scope.span().setBaggageItem("test-baggage", "foo")
|
||||||
|
ParallelBatch.of(testPromise(), testPromise())
|
||||||
|
.yield()
|
||||||
|
.map({ now ->
|
||||||
|
// close the scope now that we got the baggage inside the promises
|
||||||
|
scope.close()
|
||||||
|
return now
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
then:
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a promise that contains the active scope's "test-baggage" baggage
|
||||||
|
Promise<String> testPromise(CountDownLatch latch = null) {
|
||||||
|
Promise.sync {
|
||||||
|
latch?.await()
|
||||||
|
Scope tracerScope = GlobalTracer.get().scopeManager().active()
|
||||||
|
return tracerScope?.span()?.getBaggageItem("test-baggage")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||||
|
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.context.TraceScope;
|
||||||
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
import ratpack.exec.internal.Continuation;
|
||||||
|
import ratpack.func.Action;
|
||||||
|
import ratpack.path.PathBinding;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public final class ExecStreamInstrumentation extends Instrumenter.Default {
|
||||||
|
|
||||||
|
public ExecStreamInstrumentation() {
|
||||||
|
super("ratpack");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<? super TypeDescription> typeMatcher() {
|
||||||
|
return not(isInterface())
|
||||||
|
.and(safeHasSuperType(named("ratpack.exec.internal.DefaultExecution")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ratpack.exec.internal.DefaultExecution.delimit
|
||||||
|
@Override
|
||||||
|
public String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
packageName + ".ExecStreamInstrumentation$ActionWrapper",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
|
return Collections.singletonMap(
|
||||||
|
named("delimit")
|
||||||
|
.or(named("delimitStream"))
|
||||||
|
.and(takesArgument(0, named("ratpack.func.Action")))
|
||||||
|
.and(takesArgument(1, named("ratpack.func.Action"))),
|
||||||
|
WrapActionAdvice.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WrapActionAdvice {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static void wrap(
|
||||||
|
@Advice.Argument(value = 0, readOnly = false) Action<Throwable> onError,
|
||||||
|
@Advice.Argument(value = 1, readOnly = false) Action<Continuation> segment) {
|
||||||
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
|
if (scope instanceof TraceScope) {
|
||||||
|
final TraceScope.Continuation continuation = ((TraceScope) scope).capture();
|
||||||
|
onError = ActionWrapper.wrapIfNeeded(onError, continuation);
|
||||||
|
segment = ActionWrapper.wrapIfNeeded(segment, continuation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void muzzleCheck(final PathBinding binding) {
|
||||||
|
// This was added in 1.4. Added here to ensure consistency with other instrumentation.
|
||||||
|
binding.getDescription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public static class ActionWrapper<T> implements Action<T> {
|
||||||
|
private final Action<T> delegate;
|
||||||
|
private final TraceScope.Continuation traceContinuation;
|
||||||
|
|
||||||
|
private ActionWrapper(
|
||||||
|
final Action<T> delegate, final TraceScope.Continuation traceContinuation) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.traceContinuation = traceContinuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final T subject) throws Exception {
|
||||||
|
if (traceContinuation != null) {
|
||||||
|
try (final TraceScope scope = traceContinuation.activate()) {
|
||||||
|
scope.setAsyncPropagation(true);
|
||||||
|
delegate.execute(subject);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delegate.execute(subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Action<T> wrapIfNeeded(
|
||||||
|
final Action<T> delegate, final TraceScope.Continuation traceContinuation) {
|
||||||
|
if (delegate instanceof ActionWrapper) {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
log.debug("Wrapping action task {}", delegate);
|
||||||
|
return new ActionWrapper<>(delegate, traceContinuation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,79 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack;
|
|
||||||
|
|
||||||
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
|
||||||
import datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
public final class RatpackHttpClientInstrumentation extends Instrumenter.Default {
|
|
||||||
|
|
||||||
public static final TypeDescription.ForLoadedType URI_TYPE_DESCRIPTION =
|
|
||||||
new TypeDescription.ForLoadedType(URI.class);
|
|
||||||
|
|
||||||
public RatpackHttpClientInstrumentation() {
|
|
||||||
super(RatpackInstrumentation.EXEC_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
// FIXME: Injecting ContextualScopeManager is probably a bug. Verify and check all ratpack
|
|
||||||
// helpers before enabling.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return not(isInterface()).and(safeHasSuperType(named("ratpack.http.client.HttpClient")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
// http helpers
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpClientRequestStreamAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RatpackHttpGetAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$RequestAction",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$ResponseAction",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackHttpClientAdvice$StreamedResponseAction",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RequestSpecInjectAdapter",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.WrappedRequestSpec",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
|
||||||
final Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
|
|
||||||
transformers.put(
|
|
||||||
named("request")
|
|
||||||
.and(
|
|
||||||
takesArguments(
|
|
||||||
URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)),
|
|
||||||
RatpackHttpClientAdvice.RatpackHttpClientRequestAdvice.class.getName());
|
|
||||||
transformers.put(
|
|
||||||
named("requestStream")
|
|
||||||
.and(
|
|
||||||
takesArguments(
|
|
||||||
URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)),
|
|
||||||
RatpackHttpClientAdvice.RatpackHttpClientRequestStreamAdvice.class.getName());
|
|
||||||
transformers.put(
|
|
||||||
named("get")
|
|
||||||
.and(
|
|
||||||
takesArguments(
|
|
||||||
URI_TYPE_DESCRIPTION, RatpackInstrumentation.ACTION_TYPE_DESCRIPTION)),
|
|
||||||
RatpackHttpClientAdvice.RatpackHttpGetAdvice.class.getName());
|
|
||||||
return transformers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack;
|
|
||||||
|
|
||||||
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
|
||||||
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.isStatic;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
|
||||||
import datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
@Slf4j
|
|
||||||
public final class RatpackInstrumentation extends Instrumenter.Default {
|
|
||||||
|
|
||||||
static final String EXEC_NAME = "ratpack";
|
|
||||||
|
|
||||||
static final TypeDescription.Latent ACTION_TYPE_DESCRIPTION =
|
|
||||||
new TypeDescription.Latent("ratpack.func.Action", Modifier.PUBLIC, null);
|
|
||||||
|
|
||||||
public RatpackInstrumentation() {
|
|
||||||
super(EXEC_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("ratpack.server.internal.ServerRegistry");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
// service registry helpers
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.TracingHandler"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
|
||||||
return singletonMap(
|
|
||||||
isMethod().and(isStatic()).and(named("buildBaseRegistry")),
|
|
||||||
RatpackServerAdvice.RatpackServerRegistryAdvice.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
public static class ExecStarterInstrumentation extends Instrumenter.Default {
|
|
||||||
|
|
||||||
public ExecStarterInstrumentation() {
|
|
||||||
super(EXEC_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return not(isInterface()).and(safeHasSuperType(named("ratpack.exec.ExecStarter")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
// exec helpers
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
|
||||||
return singletonMap(
|
|
||||||
named("register").and(takesArguments(ACTION_TYPE_DESCRIPTION)),
|
|
||||||
RatpackServerAdvice.ExecStarterAdvice.class.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
public static class ExecutionInstrumentation extends Default {
|
|
||||||
|
|
||||||
public ExecutionInstrumentation() {
|
|
||||||
super(EXEC_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("ratpack.exec.Execution")
|
|
||||||
.or(not(isInterface()).and(safeHasSuperType(named("ratpack.exec.Execution"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
// exec helpers
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAdvice",
|
|
||||||
"datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$ExecStarterAction"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
|
||||||
return singletonMap(
|
|
||||||
named("fork").and(returns(named("ratpack.exec.ExecStarter"))),
|
|
||||||
RatpackServerAdvice.ExecutionAdvice.class.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||||
|
import static datadog.trace.instrumentation.ratpack.RatpackServerDecorator.DECORATE;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||||
|
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.Span;
|
||||||
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public class ServerErrorHandlerInstrumentation extends Instrumenter.Default {
|
||||||
|
|
||||||
|
public ServerErrorHandlerInstrumentation() {
|
||||||
|
super("ratpack");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
return named("ratpack.exec.Execution")
|
||||||
|
.or(not(isInterface()).and(safeHasSuperType(named("ratpack.error.ServerErrorHandler"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
"datadog.trace.agent.decorator.BaseDecorator",
|
||||||
|
"datadog.trace.agent.decorator.ServerDecorator",
|
||||||
|
"datadog.trace.agent.decorator.HttpServerDecorator",
|
||||||
|
packageName + ".RatpackServerDecorator",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
|
return singletonMap(
|
||||||
|
named("error").and(takesArgument(1, Throwable.class)), ErrorHandlerAdvice.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ErrorHandlerAdvice {
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static void captureThrowable(@Advice.Argument(1) final Throwable throwable) {
|
||||||
|
final Span span = GlobalTracer.get().activeSpan();
|
||||||
|
if (span != null) {
|
||||||
|
DECORATE.onError(span, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
@AutoService(Instrumenter.class)
|
||||||
|
public class ServerRegistryInstrumentation extends Instrumenter.Default {
|
||||||
|
|
||||||
|
public ServerRegistryInstrumentation() {
|
||||||
|
super("ratpack");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
return named("ratpack.server.internal.ServerRegistry");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
"datadog.trace.agent.decorator.BaseDecorator",
|
||||||
|
"datadog.trace.agent.decorator.ServerDecorator",
|
||||||
|
"datadog.trace.agent.decorator.HttpServerDecorator",
|
||||||
|
packageName + ".RatpackServerDecorator",
|
||||||
|
packageName + ".TracingHandler",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
|
return singletonMap(
|
||||||
|
isMethod().and(isStatic()).and(named("buildBaseRegistry")),
|
||||||
|
packageName + ".ServerRegistryAdvice");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import datadog.trace.agent.decorator.HttpServerDecorator;
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import ratpack.handling.Context;
|
||||||
|
import ratpack.http.Request;
|
||||||
|
import ratpack.http.Response;
|
||||||
|
import ratpack.http.Status;
|
||||||
|
|
||||||
|
public class RatpackServerDecorator extends HttpServerDecorator<Request, Response> {
|
||||||
|
public static final RatpackServerDecorator DECORATE = new RatpackServerDecorator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] instrumentationNames() {
|
||||||
|
return new String[] {"ratpack"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "ratpack";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(final Request request) {
|
||||||
|
return request.getMethod().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String url(final Request request) {
|
||||||
|
return request.getUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String hostname(final Request request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer port(final Request request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer status(final Response response) {
|
||||||
|
final Status status = response.getStatus();
|
||||||
|
if (status != null) {
|
||||||
|
return status.getCode();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span onContext(final Span span, final Context ctx) {
|
||||||
|
|
||||||
|
String description = ctx.getPathBinding().getDescription();
|
||||||
|
if (description == null || description.isEmpty()) {
|
||||||
|
description = ctx.getRequest().getUri();
|
||||||
|
}
|
||||||
|
if (!description.startsWith("/")) {
|
||||||
|
description = "/" + description;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String resourceName = ctx.getRequest().getMethod().getName() + " " + description;
|
||||||
|
span.setTag(DDTags.RESOURCE_NAME, resourceName);
|
||||||
|
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import ratpack.handling.HandlerDecorator;
|
||||||
|
import ratpack.registry.Registry;
|
||||||
|
|
||||||
|
public class ServerRegistryAdvice {
|
||||||
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
|
public static void injectTracing(@Advice.Return(readOnly = false) Registry registry) {
|
||||||
|
registry =
|
||||||
|
registry.join(
|
||||||
|
Registry.builder().add(HandlerDecorator.prepend(TracingHandler.INSTANCE)).build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package datadog.trace.instrumentation.ratpack;
|
||||||
|
|
||||||
|
import static datadog.trace.instrumentation.ratpack.RatpackServerDecorator.DECORATE;
|
||||||
|
|
||||||
|
import datadog.trace.context.TraceScope;
|
||||||
|
import io.netty.util.Attribute;
|
||||||
|
import io.netty.util.AttributeKey;
|
||||||
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.Tracer;
|
||||||
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
import ratpack.handling.Context;
|
||||||
|
import ratpack.handling.Handler;
|
||||||
|
import ratpack.http.Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Ratpack handler reads tracing headers from the incoming request, starts a span and ensures
|
||||||
|
* that the span is closed when the response is sent
|
||||||
|
*/
|
||||||
|
public final class TracingHandler implements Handler {
|
||||||
|
public static Handler INSTANCE = new TracingHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constant is copied over from datadog.trace.instrumentation.netty41.AttributeKeys. The key
|
||||||
|
* string must be kept consistent.
|
||||||
|
*/
|
||||||
|
public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY =
|
||||||
|
AttributeKey.valueOf(
|
||||||
|
"datadog.trace.instrumentation.netty41.server.HttpServerTracingHandler.span");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(final Context ctx) {
|
||||||
|
final Tracer tracer = GlobalTracer.get();
|
||||||
|
final Request request = ctx.getRequest();
|
||||||
|
|
||||||
|
final Attribute<Span> spanAttribute =
|
||||||
|
ctx.getDirectChannelAccess().getChannel().attr(SERVER_ATTRIBUTE_KEY);
|
||||||
|
final Span nettySpan = spanAttribute.get();
|
||||||
|
|
||||||
|
// Relying on executor instrumentation to assume the netty span is in context as the parent.
|
||||||
|
final Span ratpackSpan = tracer.buildSpan("ratpack.handler").start();
|
||||||
|
DECORATE.afterStart(ratpackSpan);
|
||||||
|
DECORATE.onRequest(ratpackSpan, request);
|
||||||
|
|
||||||
|
try (final Scope scope = tracer.scopeManager().activate(ratpackSpan, false)) {
|
||||||
|
if (scope instanceof TraceScope) {
|
||||||
|
((TraceScope) scope).setAsyncPropagation(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.getResponse()
|
||||||
|
.beforeSend(
|
||||||
|
response -> {
|
||||||
|
try (final Scope ignored = tracer.scopeManager().activate(ratpackSpan, false)) {
|
||||||
|
if (nettySpan != null) {
|
||||||
|
// Rename the netty span resource name with the ratpack route.
|
||||||
|
DECORATE.onContext(nettySpan, ctx);
|
||||||
|
}
|
||||||
|
DECORATE.onResponse(ratpackSpan, response);
|
||||||
|
DECORATE.onContext(ratpackSpan, ctx);
|
||||||
|
DECORATE.beforeFinish(ratpackSpan);
|
||||||
|
ratpackSpan.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.next();
|
||||||
|
} catch (final Throwable e) {
|
||||||
|
DECORATE.onError(ratpackSpan, e);
|
||||||
|
DECORATE.beforeFinish(ratpackSpan);
|
||||||
|
// finish since the callback probably didn't get added.
|
||||||
|
ratpackSpan.finish();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,144 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import static io.opentracing.log.Fields.ERROR_OBJECT;
|
|
||||||
|
|
||||||
import io.opentracing.Span;
|
|
||||||
import io.opentracing.tag.Tags;
|
|
||||||
import io.opentracing.util.GlobalTracer;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import ratpack.exec.Promise;
|
|
||||||
import ratpack.exec.Result;
|
|
||||||
import ratpack.func.Action;
|
|
||||||
import ratpack.http.client.ReceivedResponse;
|
|
||||||
import ratpack.http.client.RequestSpec;
|
|
||||||
import ratpack.http.client.StreamedResponse;
|
|
||||||
|
|
||||||
public class RatpackHttpClientAdvice {
|
|
||||||
public static class RequestAction implements Action<RequestSpec> {
|
|
||||||
|
|
||||||
private final Action<? super RequestSpec> requestAction;
|
|
||||||
private final AtomicReference<Span> spanRef;
|
|
||||||
|
|
||||||
public RequestAction(Action<? super RequestSpec> requestAction, AtomicReference<Span> spanRef) {
|
|
||||||
this.requestAction = requestAction;
|
|
||||||
this.spanRef = spanRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(RequestSpec requestSpec) throws Exception {
|
|
||||||
WrappedRequestSpec wrappedRequestSpec;
|
|
||||||
if (requestSpec instanceof WrappedRequestSpec) {
|
|
||||||
wrappedRequestSpec = (WrappedRequestSpec) requestSpec;
|
|
||||||
} else {
|
|
||||||
wrappedRequestSpec =
|
|
||||||
new WrappedRequestSpec(
|
|
||||||
requestSpec,
|
|
||||||
GlobalTracer.get(),
|
|
||||||
GlobalTracer.get().scopeManager().active(),
|
|
||||||
spanRef);
|
|
||||||
}
|
|
||||||
requestAction.execute(wrappedRequestSpec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ResponseAction implements Action<Result<ReceivedResponse>> {
|
|
||||||
private final AtomicReference<Span> spanRef;
|
|
||||||
|
|
||||||
public ResponseAction(AtomicReference<Span> spanRef) {
|
|
||||||
this.spanRef = spanRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Result<ReceivedResponse> result) {
|
|
||||||
Span span = spanRef.get();
|
|
||||||
if (span == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
span.finish();
|
|
||||||
if (result.isError()) {
|
|
||||||
Tags.ERROR.set(span, true);
|
|
||||||
span.log(Collections.singletonMap(ERROR_OBJECT, result.getThrowable()));
|
|
||||||
} else {
|
|
||||||
Tags.HTTP_STATUS.set(span, result.getValue().getStatusCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class StreamedResponseAction implements Action<Result<StreamedResponse>> {
|
|
||||||
private final Span span;
|
|
||||||
|
|
||||||
public StreamedResponseAction(Span span) {
|
|
||||||
this.span = span;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Result<StreamedResponse> result) {
|
|
||||||
span.finish();
|
|
||||||
if (result.isError()) {
|
|
||||||
Tags.ERROR.set(span, true);
|
|
||||||
span.log(Collections.singletonMap(ERROR_OBJECT, result.getThrowable()));
|
|
||||||
} else {
|
|
||||||
Tags.HTTP_STATUS.set(span, result.getValue().getStatusCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RatpackHttpClientRequestAdvice {
|
|
||||||
@Advice.OnMethodEnter
|
|
||||||
public static AtomicReference<Span> injectTracing(
|
|
||||||
@Advice.Argument(value = 1, readOnly = false) Action<? super RequestSpec> requestAction) {
|
|
||||||
AtomicReference<Span> span = new AtomicReference<>();
|
|
||||||
|
|
||||||
//noinspection UnusedAssignment
|
|
||||||
requestAction = new RequestAction(requestAction, span);
|
|
||||||
|
|
||||||
return span;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit
|
|
||||||
public static void finishTracing(
|
|
||||||
@Advice.Return(readOnly = false) Promise<ReceivedResponse> promise,
|
|
||||||
@Advice.Enter AtomicReference<Span> ref) {
|
|
||||||
|
|
||||||
//noinspection UnusedAssignment
|
|
||||||
promise = promise.wiretap(new ResponseAction(ref));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RatpackHttpClientRequestStreamAdvice {
|
|
||||||
@Advice.OnMethodEnter
|
|
||||||
public static AtomicReference<Span> injectTracing(
|
|
||||||
@Advice.Argument(value = 1, readOnly = false) Action<? super RequestSpec> requestAction) {
|
|
||||||
AtomicReference<Span> span = new AtomicReference<>();
|
|
||||||
|
|
||||||
//noinspection UnusedAssignment
|
|
||||||
requestAction = new RequestAction(requestAction, span);
|
|
||||||
|
|
||||||
return span;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit
|
|
||||||
public static void finishTracing(
|
|
||||||
@Advice.Return(readOnly = false) Promise<StreamedResponse> promise,
|
|
||||||
@Advice.Enter AtomicReference<Span> ref) {
|
|
||||||
Span span = ref.get();
|
|
||||||
if (span == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection UnusedAssignment
|
|
||||||
promise = promise.wiretap(new StreamedResponseAction(span));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RatpackHttpGetAdvice {
|
|
||||||
@Advice.OnMethodEnter
|
|
||||||
public static void ensureGetMethodSet(
|
|
||||||
@Advice.Argument(value = 1, readOnly = false) Action<? super RequestSpec> requestAction) {
|
|
||||||
//noinspection UnusedAssignment
|
|
||||||
requestAction = requestAction.prepend(RequestSpec::get);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import io.opentracing.propagation.TextMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import ratpack.http.Request;
|
|
||||||
import ratpack.util.MultiValueMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple request extractor in the same vein as @see
|
|
||||||
* io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter
|
|
||||||
*/
|
|
||||||
public class RatpackRequestExtractAdapter implements TextMap {
|
|
||||||
private final MultiValueMap<String, String> headers;
|
|
||||||
|
|
||||||
RatpackRequestExtractAdapter(final Request request) {
|
|
||||||
headers = request.getHeaders().asMultiValueMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Map.Entry<String, String>> iterator() {
|
|
||||||
return headers.entrySet().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(final String key, final String value) {
|
|
||||||
throw new UnsupportedOperationException("This class should be used only with Tracer.inject()!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import io.opentracing.Scope;
|
|
||||||
import io.opentracing.util.GlobalTracer;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import ratpack.exec.ExecStarter;
|
|
||||||
import ratpack.func.Action;
|
|
||||||
import ratpack.handling.HandlerDecorator;
|
|
||||||
import ratpack.registry.Registry;
|
|
||||||
import ratpack.registry.RegistrySpec;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class RatpackServerAdvice {
|
|
||||||
public static class RatpackServerRegistryAdvice {
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
|
||||||
public static void injectTracing(@Advice.Return(readOnly = false) Registry registry) {
|
|
||||||
registry =
|
|
||||||
registry.join(
|
|
||||||
Registry.builder().add(HandlerDecorator.prepend(new TracingHandler())).build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ExecStarterAdvice {
|
|
||||||
@Advice.OnMethodEnter
|
|
||||||
public static void addScopeToRegistry(
|
|
||||||
@Advice.Argument(value = 0, readOnly = false) Action<? super RegistrySpec> action) {
|
|
||||||
final Scope active = GlobalTracer.get().scopeManager().active();
|
|
||||||
if (active != null) {
|
|
||||||
action = new ExecStarterAction(active).append(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ExecutionAdvice {
|
|
||||||
@Advice.OnMethodExit
|
|
||||||
public static void addScopeToRegistry(@Advice.Return final ExecStarter starter) {
|
|
||||||
final Scope active = GlobalTracer.get().scopeManager().active();
|
|
||||||
if (active != null) {
|
|
||||||
starter.register(new ExecStarterAction(active));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ExecStarterAction implements Action<RegistrySpec> {
|
|
||||||
private final Scope active;
|
|
||||||
|
|
||||||
public ExecStarterAction(final Scope active) {
|
|
||||||
this.active = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(final RegistrySpec spec) {
|
|
||||||
if (active != null) {
|
|
||||||
spec.add(active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import io.opentracing.propagation.TextMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import ratpack.http.client.RequestSpec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SimpleTextMap to add headers to an outgoing Ratpack HttpClient request
|
|
||||||
*
|
|
||||||
* @see datadog.trace.instrumentation.apachehttpclient.DDTracingClientExec.HttpHeadersInjectAdapter
|
|
||||||
*/
|
|
||||||
public class RequestSpecInjectAdapter implements TextMap {
|
|
||||||
private final RequestSpec requestSpec;
|
|
||||||
|
|
||||||
public RequestSpecInjectAdapter(RequestSpec requestSpec) {
|
|
||||||
this.requestSpec = requestSpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Map.Entry<String, String>> iterator() {
|
|
||||||
throw new UnsupportedOperationException("Should be used only with tracer#inject()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(String key, String value) {
|
|
||||||
requestSpec.getHeaders().add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import datadog.trace.api.DDSpanTypes;
|
|
||||||
import datadog.trace.api.DDTags;
|
|
||||||
import datadog.trace.context.TraceScope;
|
|
||||||
import io.opentracing.Scope;
|
|
||||||
import io.opentracing.Span;
|
|
||||||
import io.opentracing.SpanContext;
|
|
||||||
import io.opentracing.propagation.Format;
|
|
||||||
import io.opentracing.tag.Tags;
|
|
||||||
import io.opentracing.util.GlobalTracer;
|
|
||||||
import ratpack.handling.Context;
|
|
||||||
import ratpack.handling.Handler;
|
|
||||||
import ratpack.http.Request;
|
|
||||||
import ratpack.http.Status;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Ratpack handler reads tracing headers from the incoming request, starts a scope and ensures
|
|
||||||
* that the scope is closed when the response is sent
|
|
||||||
*/
|
|
||||||
public final class TracingHandler implements Handler {
|
|
||||||
@Override
|
|
||||||
public void handle(final Context ctx) {
|
|
||||||
final Request request = ctx.getRequest();
|
|
||||||
|
|
||||||
final SpanContext extractedContext =
|
|
||||||
GlobalTracer.get()
|
|
||||||
.extract(Format.Builtin.HTTP_HEADERS, new RatpackRequestExtractAdapter(request));
|
|
||||||
|
|
||||||
final Scope scope =
|
|
||||||
GlobalTracer.get()
|
|
||||||
.buildSpan("ratpack.handler")
|
|
||||||
.asChildOf(extractedContext)
|
|
||||||
.withTag(Tags.COMPONENT.getKey(), "ratpack")
|
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
|
||||||
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_SERVER)
|
|
||||||
.withTag(Tags.HTTP_METHOD.getKey(), request.getMethod().getName())
|
|
||||||
.withTag(Tags.HTTP_URL.getKey(), request.getUri())
|
|
||||||
.startActive(false);
|
|
||||||
|
|
||||||
if (scope instanceof TraceScope) {
|
|
||||||
((TraceScope) scope).setAsyncPropagation(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Span rootSpan = scope.span();
|
|
||||||
|
|
||||||
ctx.getResponse()
|
|
||||||
.beforeSend(
|
|
||||||
response -> {
|
|
||||||
final Scope responseScope = GlobalTracer.get().scopeManager().active();
|
|
||||||
|
|
||||||
if (responseScope instanceof TraceScope) {
|
|
||||||
((TraceScope) responseScope).setAsyncPropagation(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
rootSpan.setTag(DDTags.RESOURCE_NAME, getResourceName(ctx));
|
|
||||||
final Status status = response.getStatus();
|
|
||||||
if (status != null) {
|
|
||||||
if (status.is5xx()) {
|
|
||||||
Tags.ERROR.set(rootSpan, true);
|
|
||||||
}
|
|
||||||
Tags.HTTP_STATUS.set(rootSpan, status.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
rootSpan.finish();
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.onClose(
|
|
||||||
requestOutcome -> {
|
|
||||||
final Scope activeScope = GlobalTracer.get().scopeManager().active();
|
|
||||||
if (activeScope != null) {
|
|
||||||
activeScope.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getResourceName(final Context ctx) {
|
|
||||||
String description = ctx.getPathBinding().getDescription();
|
|
||||||
if (description == null || description.isEmpty()) {
|
|
||||||
description = ctx.getRequest().getUri();
|
|
||||||
}
|
|
||||||
if (!description.startsWith("/")) {
|
|
||||||
description = "/" + description;
|
|
||||||
}
|
|
||||||
return ctx.getRequest().getMethod().getName() + " " + description;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
package datadog.trace.instrumentation.ratpack.impl;
|
|
||||||
|
|
||||||
import datadog.trace.api.DDSpanTypes;
|
|
||||||
import datadog.trace.api.DDTags;
|
|
||||||
import io.opentracing.Scope;
|
|
||||||
import io.opentracing.Span;
|
|
||||||
import io.opentracing.Tracer;
|
|
||||||
import io.opentracing.propagation.Format;
|
|
||||||
import io.opentracing.tag.Tags;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import ratpack.func.Action;
|
|
||||||
import ratpack.func.Function;
|
|
||||||
import ratpack.http.HttpMethod;
|
|
||||||
import ratpack.http.MutableHeaders;
|
|
||||||
import ratpack.http.client.ReceivedResponse;
|
|
||||||
import ratpack.http.client.RequestSpec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RequestSpec wrapper that captures the method type, sets up redirect handling and starts new spans
|
|
||||||
* when a method type is set.
|
|
||||||
*/
|
|
||||||
public final class WrappedRequestSpec implements RequestSpec {
|
|
||||||
|
|
||||||
private final RequestSpec delegate;
|
|
||||||
private final Tracer tracer;
|
|
||||||
private final Scope scope;
|
|
||||||
private final AtomicReference<Span> spanRef;
|
|
||||||
|
|
||||||
WrappedRequestSpec(
|
|
||||||
final RequestSpec spec,
|
|
||||||
final Tracer tracer,
|
|
||||||
final Scope scope,
|
|
||||||
final AtomicReference<Span> spanRef) {
|
|
||||||
delegate = spec;
|
|
||||||
this.tracer = tracer;
|
|
||||||
this.scope = scope;
|
|
||||||
this.spanRef = spanRef;
|
|
||||||
delegate.onRedirect(this::redirectHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default redirect handler that ensures the span is marked as received before
|
|
||||||
* a new span is created.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private Action<? super RequestSpec> redirectHandler(final ReceivedResponse response) {
|
|
||||||
// handler.handleReceive(response.getStatusCode(), null, span.get());
|
|
||||||
return (s) -> new WrappedRequestSpec(s, tracer, scope, spanRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec redirects(final int maxRedirects) {
|
|
||||||
delegate.redirects(maxRedirects);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec onRedirect(
|
|
||||||
final Function<? super ReceivedResponse, Action<? super RequestSpec>> function) {
|
|
||||||
|
|
||||||
final Function<? super ReceivedResponse, Action<? super RequestSpec>> wrapped =
|
|
||||||
(ReceivedResponse response) -> redirectHandler(response).append(function.apply(response));
|
|
||||||
|
|
||||||
delegate.onRedirect(wrapped);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec sslContext(final SSLContext sslContext) {
|
|
||||||
delegate.sslContext(sslContext);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MutableHeaders getHeaders() {
|
|
||||||
return delegate.getHeaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec maxContentLength(final int numBytes) {
|
|
||||||
delegate.maxContentLength(numBytes);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec headers(final Action<? super MutableHeaders> action) throws Exception {
|
|
||||||
delegate.headers(action);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec method(final HttpMethod method) {
|
|
||||||
final Span span =
|
|
||||||
tracer
|
|
||||||
.buildSpan("ratpack.client-request")
|
|
||||||
.asChildOf(scope != null ? scope.span() : null)
|
|
||||||
.withTag(Tags.COMPONENT.getKey(), "ratpack-httpclient")
|
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
|
||||||
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
|
|
||||||
.withTag(Tags.HTTP_URL.getKey(), getUri().toString())
|
|
||||||
.withTag(Tags.HTTP_METHOD.getKey(), method.getName())
|
|
||||||
.start();
|
|
||||||
spanRef.set(span);
|
|
||||||
delegate.method(method);
|
|
||||||
tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new RequestSpecInjectAdapter(this));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec decompressResponse(final boolean shouldDecompress) {
|
|
||||||
delegate.decompressResponse(shouldDecompress);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI getUri() {
|
|
||||||
return delegate.getUri();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec connectTimeout(final Duration duration) {
|
|
||||||
delegate.connectTimeout(duration);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec readTimeout(final Duration duration) {
|
|
||||||
delegate.readTimeout(duration);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Body getBody() {
|
|
||||||
return delegate.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestSpec body(final Action<? super Body> action) throws Exception {
|
|
||||||
delegate.body(action);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,21 +13,23 @@ import okhttp3.Request
|
||||||
import ratpack.exec.Promise
|
import ratpack.exec.Promise
|
||||||
import ratpack.exec.util.ParallelBatch
|
import ratpack.exec.util.ParallelBatch
|
||||||
import ratpack.groovy.test.embed.GroovyEmbeddedApp
|
import ratpack.groovy.test.embed.GroovyEmbeddedApp
|
||||||
|
import ratpack.handling.internal.HandlerException
|
||||||
import ratpack.http.HttpUrlBuilder
|
import ratpack.http.HttpUrlBuilder
|
||||||
import ratpack.http.client.HttpClient
|
import ratpack.http.client.HttpClient
|
||||||
import ratpack.path.PathBinding
|
import ratpack.path.PathBinding
|
||||||
import ratpack.test.exec.ExecHarness
|
import ratpack.test.exec.ExecHarness
|
||||||
import spock.lang.Retry
|
|
||||||
|
|
||||||
@Retry
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
import static datadog.trace.agent.test.server.http.TestHttpServer.distributedRequestTrace
|
||||||
|
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
|
||||||
|
import static datadog.trace.agent.test.utils.PortUtils.UNUSABLE_PORT
|
||||||
|
|
||||||
class RatpackTest extends AgentTestRunner {
|
class RatpackTest extends AgentTestRunner {
|
||||||
static {
|
|
||||||
System.setProperty("dd.integration.ratpack.enabled", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
OkHttpClient client = OkHttpUtils.client()
|
OkHttpClient client = OkHttpUtils.client()
|
||||||
|
|
||||||
|
|
||||||
def "test path call"() {
|
def "test path call"() {
|
||||||
setup:
|
setup:
|
||||||
def app = GroovyEmbeddedApp.ratpack {
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
@ -50,13 +52,32 @@ class RatpackTest extends AgentTestRunner {
|
||||||
resp.body.string() == "success"
|
resp.body.string() == "success"
|
||||||
|
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 1) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
resourceName "GET /"
|
resourceName "GET /"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.handler"
|
operationName "ratpack.handler"
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
parent()
|
childOf(span(0))
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
@ -95,13 +116,32 @@ class RatpackTest extends AgentTestRunner {
|
||||||
resp.body.string() == ":foo/:bar?/baz"
|
resp.body.string() == ":foo/:bar?/baz"
|
||||||
|
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 1) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
resourceName "GET /:foo/:bar?/baz"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "${app.address}a/b/baz"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
resourceName "GET /:foo/:bar?/baz"
|
resourceName "GET /:foo/:bar?/baz"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.handler"
|
operationName "ratpack.handler"
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
parent()
|
childOf(span(0))
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
@ -116,7 +156,133 @@ class RatpackTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def "test error response"() {
|
def "test handler error response"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
0 / 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
errorTags(HandlerException, Pattern.compile("java.lang.ArithmeticException: Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test promise error response"() {
|
||||||
|
setup:
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get {
|
||||||
|
Promise.async {
|
||||||
|
0 / 0
|
||||||
|
}.then {
|
||||||
|
context.render(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test render error response"() {
|
||||||
setup:
|
setup:
|
||||||
def app = GroovyEmbeddedApp.ratpack {
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
handlers {
|
handlers {
|
||||||
|
@ -137,13 +303,33 @@ class RatpackTest extends AgentTestRunner {
|
||||||
resp.code() == 500
|
resp.code() == 500
|
||||||
|
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 1) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
errorTags(ArithmeticException, Pattern.compile("Division( is)? undefined"))
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
resourceName "GET /"
|
resourceName "GET /"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.handler"
|
operationName "ratpack.handler"
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
parent()
|
childOf(span(0))
|
||||||
errored true
|
errored true
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
@ -151,8 +337,7 @@ class RatpackTest extends AgentTestRunner {
|
||||||
"$Tags.HTTP_METHOD.key" "GET"
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
"$Tags.HTTP_STATUS.key" 500
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
"$Tags.HTTP_URL.key" "/"
|
"$Tags.HTTP_URL.key" "/"
|
||||||
"error" true
|
"$Tags.ERROR.key" true
|
||||||
// errorTags(Exception, String) // TODO: find out how to get throwable in instrumentation
|
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,13 +348,16 @@ class RatpackTest extends AgentTestRunner {
|
||||||
def "test path call using ratpack http client"() {
|
def "test path call using ratpack http client"() {
|
||||||
setup:
|
setup:
|
||||||
|
|
||||||
def external = GroovyEmbeddedApp.ratpack {
|
// Use jetty based server to avoid confusion.
|
||||||
|
def external = httpServer {
|
||||||
handlers {
|
handlers {
|
||||||
get("nested") {
|
get("nested") {
|
||||||
context.render("succ")
|
handleDistributedRequest()
|
||||||
|
response.send("succ")
|
||||||
}
|
}
|
||||||
get("nested2") {
|
get("nested2") {
|
||||||
context.render("ess")
|
handleDistributedRequest()
|
||||||
|
response.send("ess")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,53 +394,37 @@ class RatpackTest extends AgentTestRunner {
|
||||||
// 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)
|
||||||
assertTraces(3) {
|
assertTraces(3) {
|
||||||
// simulated external system, first call
|
distributedRequestTrace(it, 0, trace(2).get(3))
|
||||||
trace(0, 1) {
|
distributedRequestTrace(it, 1, trace(2).get(2))
|
||||||
span(0) {
|
|
||||||
resourceName "GET /nested"
|
trace(2, 4) {
|
||||||
serviceName "unnamed-java-app"
|
|
||||||
operationName "ratpack.handler"
|
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
|
||||||
childOf(trace(2).get(2))
|
|
||||||
errored false
|
|
||||||
tags {
|
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_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" "ratpack"
|
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_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
|
// main app span that processed the request from OKHTTP request
|
||||||
span(0) {
|
span(0) {
|
||||||
resourceName "GET /"
|
resourceName "GET /"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.handler"
|
operationName "netty.request"
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
parent()
|
parent()
|
||||||
errored false
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
@ -263,36 +435,122 @@ class RatpackTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Second http client call that receives the 'ess' of Success
|
// Second http client call that receives the 'ess' of Success
|
||||||
span(1) {
|
span(2) {
|
||||||
resourceName "GET /?"
|
resourceName "GET /?"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.client-request"
|
operationName "netty.client.request"
|
||||||
spanType DDSpanTypes.HTTP_CLIENT
|
spanType DDSpanTypes.HTTP_CLIENT
|
||||||
childOf(span(0))
|
childOf(span(3))
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack-httpclient"
|
"$Tags.COMPONENT.key" "netty-client"
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$Tags.HTTP_METHOD.key" "GET"
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
"$Tags.HTTP_STATUS.key" 200
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
"$Tags.HTTP_URL.key" "${external.address}nested2"
|
"$Tags.HTTP_URL.key" "${external.address}/nested2"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// First http client call that receives the 'Succ' of Success
|
// First http client call that receives the 'Succ' of Success
|
||||||
span(2) {
|
span(3) {
|
||||||
resourceName "GET /nested"
|
resourceName "GET /nested"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.client-request"
|
operationName "netty.client.request"
|
||||||
spanType DDSpanTypes.HTTP_CLIENT
|
spanType DDSpanTypes.HTTP_CLIENT
|
||||||
childOf(span(0))
|
childOf(span(1))
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack-httpclient"
|
"$Tags.COMPONENT.key" "netty-client"
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$Tags.HTTP_METHOD.key" "GET"
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
"$Tags.HTTP_STATUS.key" 200
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
"$Tags.HTTP_URL.key" "${external.address}nested"
|
"$Tags.HTTP_URL.key" "${external.address}/nested"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test ratpack http client error handling"() {
|
||||||
|
setup:
|
||||||
|
def badAddress = new URI("http://localhost:$UNUSABLE_PORT")
|
||||||
|
|
||||||
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
|
handlers {
|
||||||
|
get { HttpClient httpClient ->
|
||||||
|
httpClient.get(badAddress)
|
||||||
|
.map { it.body.text }
|
||||||
|
.then {
|
||||||
|
context.render(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def request = new Request.Builder()
|
||||||
|
.url(app.address.toURL())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def resp = client.newCall(request).execute()
|
||||||
|
|
||||||
|
then:
|
||||||
|
resp.code() == 500
|
||||||
|
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 3) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
"$Tags.ERROR.key" true
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(1) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.handler"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
childOf(span(0))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 500
|
||||||
|
"$Tags.HTTP_URL.key" "/"
|
||||||
|
errorTags(ConnectException, String)
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(2) {
|
||||||
|
operationName "netty.connect"
|
||||||
|
resourceName "netty.connect"
|
||||||
|
childOf(span(1))
|
||||||
|
errored true
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
errorTags(ConnectException, String)
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,26 +563,24 @@ class RatpackTest extends AgentTestRunner {
|
||||||
def app = GroovyEmbeddedApp.ratpack {
|
def app = GroovyEmbeddedApp.ratpack {
|
||||||
handlers {
|
handlers {
|
||||||
get {
|
get {
|
||||||
final Scope scope = !startSpanInHandler ? GlobalTracer.get().scopeManager().active() :
|
TraceScope scope
|
||||||
GlobalTracer.get()
|
if (startSpanInHandler) {
|
||||||
|
Span childSpan = GlobalTracer.get()
|
||||||
.buildSpan("ratpack.exec-test")
|
.buildSpan("ratpack.exec-test")
|
||||||
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
|
.withTag(DDTags.RESOURCE_NAME, "INSIDE-TEST")
|
||||||
.startActive(false)
|
.start()
|
||||||
|
scope = GlobalTracer.get().scopeManager().activate(childSpan, true)
|
||||||
if (startSpanInHandler) {
|
|
||||||
((TraceScope) scope).setAsyncPropagation(true)
|
|
||||||
}
|
}
|
||||||
scope.span().setBaggageItem("test-baggage", "foo")
|
def latch = new CountDownLatch(1)
|
||||||
|
try {
|
||||||
|
scope?.setAsyncPropagation(true)
|
||||||
|
GlobalTracer.get().activeSpan().setBaggageItem("test-baggage", "foo")
|
||||||
|
|
||||||
final Span startedSpan = startSpanInHandler ? scope.span() : null
|
context.render(testPromise(latch).fork())
|
||||||
if (startSpanInHandler) {
|
} finally {
|
||||||
scope.close()
|
scope?.close()
|
||||||
context.onClose {
|
latch.countDown()
|
||||||
startedSpan.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.render(testPromise().fork())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,13 +597,44 @@ class RatpackTest extends AgentTestRunner {
|
||||||
resp.body().string() == "foo"
|
resp.body().string() == "foo"
|
||||||
|
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, (startSpanInHandler ? 2 : 1)) {
|
trace(0, (startSpanInHandler ? 3 : 2)) {
|
||||||
|
if (startSpanInHandler) {
|
||||||
|
span(0) {
|
||||||
|
resourceName "INSIDE-TEST"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "ratpack.exec-test"
|
||||||
|
childOf(span(2))
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
span(startSpanInHandler ? 1 : 0) {
|
span(startSpanInHandler ? 1 : 0) {
|
||||||
|
resourceName "GET /"
|
||||||
|
serviceName "unnamed-java-app"
|
||||||
|
operationName "netty.request"
|
||||||
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" "netty"
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_SERVER
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" 200
|
||||||
|
"$Tags.HTTP_URL.key" "$app.address"
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "$app.address.host"
|
||||||
|
"$Tags.PEER_HOST_IPV4.key" "127.0.0.1"
|
||||||
|
"$Tags.PEER_PORT.key" Integer
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(startSpanInHandler ? 2 : 1) {
|
||||||
resourceName "GET /"
|
resourceName "GET /"
|
||||||
serviceName "unnamed-java-app"
|
serviceName "unnamed-java-app"
|
||||||
operationName "ratpack.handler"
|
operationName "ratpack.handler"
|
||||||
spanType DDSpanTypes.HTTP_SERVER
|
spanType DDSpanTypes.HTTP_SERVER
|
||||||
parent()
|
childOf(span(startSpanInHandler ? 1 : 0))
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "ratpack"
|
"$Tags.COMPONENT.key" "ratpack"
|
||||||
|
@ -358,18 +645,6 @@ class RatpackTest extends AgentTestRunner {
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startSpanInHandler) {
|
|
||||||
span(0) {
|
|
||||||
resourceName "INSIDE-TEST"
|
|
||||||
serviceName "unnamed-java-app"
|
|
||||||
operationName "ratpack.exec-test"
|
|
||||||
childOf(span(1))
|
|
||||||
errored false
|
|
||||||
tags {
|
|
||||||
defaultTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,10 +691,11 @@ class RatpackTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a promise that contains the active scope's "test-baggage" baggage
|
// returns a promise that contains the active scope's "test-baggage" baggage
|
||||||
Promise<String> testPromise() {
|
Promise<String> testPromise(CountDownLatch latch = null) {
|
||||||
Promise.sync {
|
Promise.sync {
|
||||||
|
latch?.await()
|
||||||
Scope tracerScope = GlobalTracer.get().scopeManager().active()
|
Scope tracerScope = GlobalTracer.get().scopeManager().active()
|
||||||
return tracerScope.span().getBaggageItem("test-baggage")
|
return tracerScope?.span()?.getBaggageItem("test-baggage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,13 +52,13 @@ class TagsAssert {
|
||||||
errorTags(errorType, null)
|
errorTags(errorType, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
def errorTags(Class<Throwable> errorType, Object message) {
|
def errorTags(Class<Throwable> errorType, message) {
|
||||||
methodMissing("error", [true].toArray())
|
tag("error", true)
|
||||||
methodMissing("error.type", [errorType.name].toArray())
|
tag("error.type", errorType.name)
|
||||||
methodMissing("error.stack", [String].toArray())
|
tag("error.stack", String)
|
||||||
|
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
methodMissing("error.msg", [message].toArray())
|
tag("error.msg", message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ class TestHttpServer implements AutoCloseable {
|
||||||
assert body != null
|
assert body != null
|
||||||
|
|
||||||
send()
|
send()
|
||||||
|
resp.setContentLength(body.bytes.length)
|
||||||
resp.writer.print(body)
|
resp.writer.print(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package datadog.trace.context;
|
package datadog.trace.context;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
/** An object when can propagate a datadog trace across multiple threads. */
|
/** An object when can propagate a datadog trace across multiple threads. */
|
||||||
public interface TraceScope {
|
public interface TraceScope extends Closeable {
|
||||||
/**
|
/**
|
||||||
* Prevent the trace attached to this TraceScope from reporting until the returned Continuation
|
* Prevent the trace attached to this TraceScope from reporting until the returned Continuation
|
||||||
* finishes.
|
* finishes.
|
||||||
|
@ -11,6 +13,7 @@ public interface TraceScope {
|
||||||
Continuation capture();
|
Continuation capture();
|
||||||
|
|
||||||
/** Close the activated context and allow any underlying spans to finish. */
|
/** Close the activated context and allow any underlying spans to finish. */
|
||||||
|
@Override
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
/** If true, this context will propagate across async boundaries. */
|
/** If true, this context will propagate across async boundaries. */
|
||||||
|
|
|
@ -293,6 +293,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
|
||||||
spanContextDecorators.put(decorator.getMatchingTag(), list);
|
spanContextDecorators.put(decorator.getMatchingTag(), list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void addScopeContext(final ScopeContext context) {
|
public void addScopeContext(final ScopeContext context) {
|
||||||
scopeManager.addScopeContext(context);
|
scopeManager.addScopeContext(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,13 @@ public class ContextualScopeManager implements ScopeManager {
|
||||||
return tlsScope.get();
|
return tlsScope.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void addScopeContext(final ScopeContext context) {
|
public void addScopeContext(final ScopeContext context) {
|
||||||
scopeContexts.addFirst(context);
|
scopeContexts.addFirst(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attach a listener to scope activation events */
|
/** Attach a listener to scope activation events */
|
||||||
public void addScopeListener(ScopeListener listener) {
|
public void addScopeListener(final ScopeListener listener) {
|
||||||
scopeListeners.add(listener);
|
scopeListeners.add(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package datadog.opentracing.scopemanager;
|
||||||
import io.opentracing.ScopeManager;
|
import io.opentracing.ScopeManager;
|
||||||
|
|
||||||
/** Represents a ScopeManager that is only valid in certain cases such as on a specific thread. */
|
/** Represents a ScopeManager that is only valid in certain cases such as on a specific thread. */
|
||||||
|
@Deprecated
|
||||||
public interface ScopeContext extends ScopeManager {
|
public interface ScopeContext extends ScopeManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue