No matter what, it won't work :) I am now in the mood 'try everything in the world until it works'

This commit is contained in:
Luca Abbati 2019-07-16 15:38:44 +02:00
parent cb430c566b
commit 840b8b407d
No known key found for this signature in database
GPG Key ID: 74DBB952D9BA17F2
10 changed files with 382 additions and 324 deletions

View File

@ -1,42 +1,53 @@
package datadog.trace.agent.tooling;
import datadog.trace.bootstrap.WeakMap;
import java.util.HashMap;
import java.util.Map;
//import datadog.trace.bootstrap.WeakMap;
//import java.util.HashMap;
//import java.util.Map;
/** A registry which is scoped per-classloader able to hold key-value pairs with weak keys. */
public class ClassLoaderScopedWeakMap {
public static final ClassLoaderScopedWeakMap INSTANCE = new ClassLoaderScopedWeakMap();
// public static final ClassLoaderScopedWeakMap INSTANCE = new ClassLoaderScopedWeakMap();
private final WeakMap<ClassLoader, Map<Object, Object>> map = WeakMap.Supplier.DEFAULT.get();
// private final WeakMap<ClassLoader, Map<Object, Object>> map = WeakMap.Supplier.DEFAULT.get();
/**
* Gets the element registered at the specified key or register as new one retrieved by the
* provided supplier.
*/
public synchronized Object getOrCreate(
ClassLoader classLoader, Object key, Supplier valueSupplier) {
Map<Object, Object> classLoaderMap = map.get(classLoader);
if (classLoaderMap == null) {
classLoaderMap = new HashMap<>();
map.put(classLoader, classLoaderMap);
// public Object getOrCreate(
//// public synchronized Object getOrCreate(
// ClassLoader classLoader, Object key, Supplier valueSupplier) {
//// Map<Object, Object> classLoaderMap = map.get(classLoader);
//// if (classLoaderMap == null) {
//// classLoaderMap = new HashMap<>();
//// map.put(classLoader, classLoaderMap);
//// }
////
//// if (classLoaderMap.containsKey(key)) {
//// return classLoaderMap.get(key);
//// }
//
// Object value = valueSupplier.get();
//// classLoaderMap.put(key, value);
// return value;
// }
public static Object aaa(Object aaa) {
System.out.println("[STD LOG] aaa " + ClassLoaderScopedWeakMapSupplier.class.getName());
return aaa;
}
if (classLoaderMap.containsKey(key)) {
return classLoaderMap.get(key);
public static Object bbb(ClassLoaderScopedWeakMapSupplier aaa) {
System.out.println("[STD LOG] bbb" + ClassLoaderScopedWeakMapSupplier.class.getName());
return aaa.get();
}
Object value = valueSupplier.get();
classLoaderMap.put(key, value);
return value;
}
/**
* Supplies the value to be stored and it is called only when a value does not exists yet in the
* registry.
*/
public interface Supplier {
Object get();
}
// /**
// * Supplies the value to be stored and it is called only when a value does not exists yet in the
// * registry.
// */
// public interface Supplier {
// Object get();
// }
}

View File

@ -0,0 +1,5 @@
package datadog.trace.agent.tooling;
public interface ClassLoaderScopedWeakMapSupplier {
Object get();
}

View File

@ -60,3 +60,23 @@ configurations.testCompile {
}
}
}
test {
testLogging {
// Make sure output from
// standard out or error is shown
// in Gradle output.
showStandardStreams = true
// Or we use events method:
// events 'standard_out', 'standard_error'
// Or set property events:
// events = ['standard_out', 'standard_error']
// Instead of string values we can
// use enum values:
// events org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_OUT,
// org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_ERROR,
}
}

View File

@ -1,6 +1,7 @@
package datadog.trace.instrumentation.netty40;
import datadog.trace.agent.tooling.ClassLoaderScopedWeakMap;
import datadog.trace.agent.tooling.ClassLoaderScopedWeakMapSupplier;
import datadog.trace.context.TraceScope;
import datadog.trace.instrumentation.netty40.client.HttpClientTracingHandler;
import datadog.trace.instrumentation.netty40.server.HttpServerTracingHandler;
@ -9,49 +10,65 @@ import io.opentracing.Span;
public class AttributeKeys {
static {
System.out.println("Canone!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
private static final String PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME =
"datadog.trace.instrumentation.netty40.parent.connect.continuation";
public static final AttributeKey<TraceScope.Continuation>
PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY =
(AttributeKey<TraceScope.Continuation>)
ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
AttributeKey.class.getClassLoader(),
PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME,
new ClassLoaderScopedWeakMap.Supplier() {
@Override
public Object get() {
return new AttributeKey<>(PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME);
}
});
PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY = new AttributeKey<>(PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME);
// public static final AttributeKey<TraceScope.Continuation>
// PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY =
// (AttributeKey<TraceScope.Continuation>)
// ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
// AttributeKey.class.getClassLoader(),
// PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME,
// new ClassLoaderScopedWeakMap.Supplier() {
// @Override
// public Object get() {
// return new AttributeKey<>(PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY_NAME);
// }
// });
private static final String SERVER_ATTRIBUTE_KEY_NAME =
HttpServerTracingHandler.class.getName() + ".span";
public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY =
(AttributeKey<Span>)
ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
AttributeKey.class.getClassLoader(),
SERVER_ATTRIBUTE_KEY_NAME,
new ClassLoaderScopedWeakMap.Supplier() {
@Override
public Object get() {
return new AttributeKey<>(SERVER_ATTRIBUTE_KEY_NAME);
}
});
public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY = new AttributeKey<>(SERVER_ATTRIBUTE_KEY_NAME);
// public static final AttributeKey<Span> SERVER_ATTRIBUTE_KEY =
// (AttributeKey<Span>)
// ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
// AttributeKey.class.getClassLoader(),
// SERVER_ATTRIBUTE_KEY_NAME,
// new ClassLoaderScopedWeakMap.Supplier() {
// @Override
// public Object get() {
// return new AttributeKey<>(SERVER_ATTRIBUTE_KEY_NAME);
// }
// });
private static final String CLIENT_ATTRIBUTE_KEY_NAME =
HttpClientTracingHandler.class.getName() + ".span";
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
(AttributeKey<Span>)
ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
AttributeKey.class.getClassLoader(),
CLIENT_ATTRIBUTE_KEY_NAME,
new ClassLoaderScopedWeakMap.Supplier() {
// public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY = new AttributeKey<>(CLIENT_ATTRIBUTE_KEY_NAME);
// public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY = (AttributeKey<Span>) ClassLoaderScopedWeakMap.aaa(new AttributeKey<>(CLIENT_ATTRIBUTE_KEY_NAME));
public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY = (AttributeKey<Span>) ClassLoaderScopedWeakMap.bbb(new ClassLoaderScopedWeakMapSupplier() {
@Override
public Object get() {
System.out.println("[STD LOG] executing the getter");
return new AttributeKey<>(CLIENT_ATTRIBUTE_KEY_NAME);
}
});
// public static final AttributeKey<Span> CLIENT_ATTRIBUTE_KEY =
// (AttributeKey<Span>)
// ClassLoaderScopedWeakMap.INSTANCE.getOrCreate(
// AttributeKey.class.getClassLoader(),
// CLIENT_ATTRIBUTE_KEY_NAME,
// new ClassLoaderScopedWeakMap.Supplier() {
// @Override
// public Object get() {
// return new AttributeKey<>(CLIENT_ATTRIBUTE_KEY_NAME);
// }
// });
}

View File

@ -41,6 +41,8 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
@Override
public String[] helperClassNames() {
return new String[] {
"datadog.trace.agent.tooling.ClassLoaderScopedWeakMapSupplier",
"datadog.trace.agent.tooling.ClassLoaderScopedWeakMap",
packageName + ".AttributeKeys",
"datadog.trace.agent.decorator.BaseDecorator",
// client helpers

View File

@ -55,6 +55,8 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Default {
@Override
public String[] helperClassNames() {
return new String[] {
"datadog.trace.agent.tooling.ClassLoaderScopedWeakMapSupplier",
"datadog.trace.agent.tooling.ClassLoaderScopedWeakMap",
packageName + ".AttributeKeys",
"datadog.trace.agent.decorator.BaseDecorator",
// client helpers

View File

@ -20,6 +20,7 @@ public class HttpClientRequestTracingHandler extends ChannelOutboundHandlerAdapt
@Override
public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise prm) {
System.out.println("[STD LOG] About to write request handler");
if (!(msg instanceof HttpRequest)) {
ctx.write(msg, prm);
return;

View File

@ -50,45 +50,45 @@ class Netty40ClientTest extends HttpClientTest<NettyHttpClientDecorator> {
false
}
def "connection error (unopened port)"() {
given:
def uri = new URI("http://localhost:$UNUSABLE_PORT/")
when:
runUnderTrace("parent") {
doRequest(method, uri)
}
then:
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
and:
assertTraces(1) {
trace(0, 2) {
basicSpan(it, 0, "parent", thrownException)
span(1) {
operationName "netty.connect"
resourceName "netty.connect"
childOf span(0)
errored true
tags {
"$Tags.COMPONENT.key" "netty"
Class errorClass = ConnectException
try {
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
} catch (ClassNotFoundException e) {
// Older versions use 'java.net.ConnectException' and do not have 'io.netty.channel.AbstractChannel$AnnotatedConnectException'
}
errorTags errorClass, "Connection refused: localhost/127.0.0.1:$UNUSABLE_PORT"
defaultTags()
}
}
}
}
where:
method = "GET"
}
// def "connection error (unopened port)"() {
// given:
// def uri = new URI("http://localhost:$UNUSABLE_PORT/")
//
// when:
// runUnderTrace("parent") {
// doRequest(method, uri)
// }
//
// then:
// def ex = thrown(Exception)
// def thrownException = ex instanceof ExecutionException ? ex.cause : ex
//
// and:
// assertTraces(1) {
// trace(0, 2) {
// basicSpan(it, 0, "parent", thrownException)
//
// span(1) {
// operationName "netty.connect"
// resourceName "netty.connect"
// childOf span(0)
// errored true
// tags {
// "$Tags.COMPONENT.key" "netty"
// Class errorClass = ConnectException
// try {
// errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
// } catch (ClassNotFoundException e) {
// // Older versions use 'java.net.ConnectException' and do not have 'io.netty.channel.AbstractChannel$AnnotatedConnectException'
// }
// errorTags errorClass, "Connection refused: localhost/127.0.0.1:$UNUSABLE_PORT"
// defaultTags()
// }
// }
// }
// }
//
// where:
// method = "GET"
// }
}

View File

@ -88,232 +88,232 @@ abstract class HttpClientTest<T extends HttpClientDecorator> extends AgentTestRu
where:
path | tagQueryString
"/success" | false
"/success" | true
"/success?with=params" | false
"/success?with=params" | true
"/success#with+fragment" | true
"/success?with=params#and=fragment" | true
// "/success" | true
// "/success?with=params" | false
// "/success?with=params" | true
// "/success#with+fragment" | true
// "/success?with=params#and=fragment" | true
method = "GET"
url = server.address.resolve(path)
}
@Unroll
def "basic #method request with parent"() {
when:
def status = runUnderTrace("parent") {
doRequest(method, server.address.resolve("/success"))
}
then:
status == 200
assertTraces(2) {
server.distributedRequestTrace(it, 0, trace(1).last())
trace(1, size(2)) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method, false)
}
}
where:
method << BODY_METHODS
}
@Unroll
def "basic #method request with split-by-domain"() {
when:
def status = withConfigOverride(Config.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true") {
doRequest(method, server.address.resolve("/success"))
}
then:
status == 200
assertTraces(2) {
server.distributedRequestTrace(it, 0, trace(1).last())
trace(1, size(1)) {
clientSpan(it, 0, null, method, true)
}
}
where:
method = "HEAD"
}
def "trace request without propagation"() {
when:
def status = withConfigOverride(Config.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "$renameService") {
runUnderTrace("parent") {
doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"])
}
}
then:
status == 200
// only one trace (client).
assertTraces(1) {
trace(0, size(2)) {
basicSpan(it, 0, "parent")
clientSpan(it, 1, span(0), method, renameService)
}
}
where:
method = "GET"
renameService << [false, true]
}
def "trace request with callback and parent"() {
when:
def status = runUnderTrace("parent") {
doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"]) {
runUnderTrace("child") {}
}
}
then:
status == 200
// only one trace (client).
assertTraces(1) {
trace(0, size(3)) {
basicSpan(it, 0, "parent")
span(1) {
operationName "child"
childOf span(0)
}
clientSpan(it, 2, span(0), method, false)
}
}
where:
method = "GET"
}
def "trace request with callback and no parent"() {
when:
def status = doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"]) {
runUnderTrace("child") {
// Ensure consistent ordering of traces for assertion.
TEST_WRITER.waitForTraces(1)
}
}
then:
status == 200
// only one trace (client).
assertTraces(2) {
trace(0, size(1)) {
clientSpan(it, 0, null, method, false)
}
trace(1, 1) {
span(0) {
operationName "child"
parent()
}
}
}
where:
method = "GET"
}
@Unroll
def "basic #method request with 1 redirect"() {
given:
assumeTrue(testRedirects())
def uri = server.address.resolve("/redirect")
when:
def status = doRequest(method, uri)
then:
status == 200
assertTraces(3) {
server.distributedRequestTrace(it, 0, trace(2).last())
server.distributedRequestTrace(it, 1, trace(2).last())
trace(2, size(1)) {
clientSpan(it, 0, null, method, false, false, uri)
}
}
where:
method = "GET"
}
@Unroll
def "basic #method request with 2 redirects"() {
given:
assumeTrue(testRedirects())
def uri = server.address.resolve("/another-redirect")
when:
def status = doRequest(method, uri)
then:
status == 200
assertTraces(4) {
server.distributedRequestTrace(it, 0, trace(3).last())
server.distributedRequestTrace(it, 1, trace(3).last())
server.distributedRequestTrace(it, 2, trace(3).last())
trace(3, size(1)) {
clientSpan(it, 0, null, method, false, false, uri)
}
}
where:
method = "GET"
}
@Unroll
def "basic #method request with circular redirects"() {
given:
assumeTrue(testRedirects())
def uri = server.address.resolve("/circular-redirect")
when:
doRequest(method, uri)//, ["is-dd-server": "false"])
then:
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
and:
assertTraces(3) {
server.distributedRequestTrace(it, 0, trace(2).last())
server.distributedRequestTrace(it, 1, trace(2).last())
trace(2, size(1)) {
clientSpan(it, 0, null, method, false, false, uri, statusOnRedirectError(), thrownException)
}
}
where:
method = "GET"
}
def "connection error (unopened port)"() {
given:
assumeTrue(testConnectionFailure())
def uri = new URI("http://localhost:$UNUSABLE_PORT/")
when:
runUnderTrace("parent") {
doRequest(method, uri)
}
then:
def ex = thrown(Exception)
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
and:
assertTraces(1) {
trace(0, 2) {
basicSpan(it, 0, "parent", thrownException)
clientSpan(it, 1, span(0), method, false, false, uri, null, thrownException)
}
}
where:
method = "GET"
}
// @Unroll
// def "basic #method request with parent"() {
// when:
// def status = runUnderTrace("parent") {
// doRequest(method, server.address.resolve("/success"))
// }
//
// then:
// status == 200
// assertTraces(2) {
// server.distributedRequestTrace(it, 0, trace(1).last())
// trace(1, size(2)) {
// basicSpan(it, 0, "parent")
// clientSpan(it, 1, span(0), method, false)
// }
// }
//
// where:
// method << BODY_METHODS
// }
//
// @Unroll
// def "basic #method request with split-by-domain"() {
// when:
// def status = withConfigOverride(Config.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true") {
// doRequest(method, server.address.resolve("/success"))
// }
//
// then:
// status == 200
// assertTraces(2) {
// server.distributedRequestTrace(it, 0, trace(1).last())
// trace(1, size(1)) {
// clientSpan(it, 0, null, method, true)
// }
// }
//
// where:
// method = "HEAD"
// }
//
// def "trace request without propagation"() {
// when:
// def status = withConfigOverride(Config.HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "$renameService") {
// runUnderTrace("parent") {
// doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"])
// }
// }
//
// then:
// status == 200
// // only one trace (client).
// assertTraces(1) {
// trace(0, size(2)) {
// basicSpan(it, 0, "parent")
// clientSpan(it, 1, span(0), method, renameService)
// }
// }
//
// where:
// method = "GET"
// renameService << [false, true]
// }
//
// def "trace request with callback and parent"() {
// when:
// def status = runUnderTrace("parent") {
// doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"]) {
// runUnderTrace("child") {}
// }
// }
//
// then:
// status == 200
// // only one trace (client).
// assertTraces(1) {
// trace(0, size(3)) {
// basicSpan(it, 0, "parent")
// span(1) {
// operationName "child"
// childOf span(0)
// }
// clientSpan(it, 2, span(0), method, false)
// }
// }
//
// where:
// method = "GET"
// }
//
// def "trace request with callback and no parent"() {
// when:
// def status = doRequest(method, server.address.resolve("/success"), ["is-dd-server": "false"]) {
// runUnderTrace("child") {
// // Ensure consistent ordering of traces for assertion.
// TEST_WRITER.waitForTraces(1)
// }
// }
//
// then:
// status == 200
// // only one trace (client).
// assertTraces(2) {
// trace(0, size(1)) {
// clientSpan(it, 0, null, method, false)
// }
// trace(1, 1) {
// span(0) {
// operationName "child"
// parent()
// }
// }
// }
//
// where:
// method = "GET"
// }
//
// @Unroll
// def "basic #method request with 1 redirect"() {
// given:
// assumeTrue(testRedirects())
// def uri = server.address.resolve("/redirect")
//
// when:
// def status = doRequest(method, uri)
//
// then:
// status == 200
// assertTraces(3) {
// server.distributedRequestTrace(it, 0, trace(2).last())
// server.distributedRequestTrace(it, 1, trace(2).last())
// trace(2, size(1)) {
// clientSpan(it, 0, null, method, false, false, uri)
// }
// }
//
// where:
// method = "GET"
// }
//
// @Unroll
// def "basic #method request with 2 redirects"() {
// given:
// assumeTrue(testRedirects())
// def uri = server.address.resolve("/another-redirect")
//
// when:
// def status = doRequest(method, uri)
//
// then:
// status == 200
// assertTraces(4) {
// server.distributedRequestTrace(it, 0, trace(3).last())
// server.distributedRequestTrace(it, 1, trace(3).last())
// server.distributedRequestTrace(it, 2, trace(3).last())
// trace(3, size(1)) {
// clientSpan(it, 0, null, method, false, false, uri)
// }
// }
//
// where:
// method = "GET"
// }
//
// @Unroll
// def "basic #method request with circular redirects"() {
// given:
// assumeTrue(testRedirects())
// def uri = server.address.resolve("/circular-redirect")
//
// when:
// doRequest(method, uri)//, ["is-dd-server": "false"])
//
// then:
// def ex = thrown(Exception)
// def thrownException = ex instanceof ExecutionException ? ex.cause : ex
//
// and:
// assertTraces(3) {
// server.distributedRequestTrace(it, 0, trace(2).last())
// server.distributedRequestTrace(it, 1, trace(2).last())
// trace(2, size(1)) {
// clientSpan(it, 0, null, method, false, false, uri, statusOnRedirectError(), thrownException)
// }
// }
//
// where:
// method = "GET"
// }
//
// def "connection error (unopened port)"() {
// given:
// assumeTrue(testConnectionFailure())
// def uri = new URI("http://localhost:$UNUSABLE_PORT/")
//
// when:
// runUnderTrace("parent") {
// doRequest(method, uri)
// }
//
// then:
// def ex = thrown(Exception)
// def thrownException = ex instanceof ExecutionException ? ex.cause : ex
//
// and:
// assertTraces(1) {
// trace(0, 2) {
// basicSpan(it, 0, "parent", thrownException)
// clientSpan(it, 1, span(0), method, false, false, uri, null, thrownException)
// }
// }
//
// where:
// method = "GET"
// }
// parent span must be cast otherwise it breaks debugging classloading (junit loads it early)
void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean renameService = false, boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) {

View File

@ -38,7 +38,7 @@ public class ListWriter extends CopyOnWriteArrayList<List<DDSpan>> implements Wr
}
latches.add(latch);
}
if (!latch.await(20, TimeUnit.SECONDS)) {
if (!latch.await(5, TimeUnit.SECONDS)) {
throw new TimeoutException(
"Timeout waiting for " + number + " trace(s). ListWriter.size() == " + size());
}