Merge pull request #613 from DataDog/mar-kolya/improve-httpurl-connection
Improve HttpUrlConnection instrumentation
This commit is contained in:
commit
7cd3438d6b
|
@ -29,6 +29,10 @@ public class MongoAsyncClientInstrumentationTest {
|
||||||
public static void setup() throws Exception {
|
public static void setup() throws Exception {
|
||||||
IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer);
|
IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer);
|
||||||
MongoClientInstrumentationTest.startLocalMongo();
|
MongoClientInstrumentationTest.startLocalMongo();
|
||||||
|
// Embeded Mongo uses HttpUrlConnection to download things so we have to clear traces before
|
||||||
|
// going to tests
|
||||||
|
writer.clear();
|
||||||
|
|
||||||
client = MongoClients.create("mongodb://" + MONGO_HOST + ":" + MONGO_PORT);
|
client = MongoClients.create("mongodb://" + MONGO_HOST + ":" + MONGO_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +54,7 @@ public class MongoAsyncClientInstrumentationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void insertOperation() throws InterruptedException, Exception {
|
public void insertOperation() throws Exception {
|
||||||
final MongoDatabase db = client.getDatabase(MONGO_DB_NAME);
|
final MongoDatabase db = client.getDatabase(MONGO_DB_NAME);
|
||||||
final String collectionName = "asyncCollection";
|
final String collectionName = "asyncCollection";
|
||||||
final AtomicBoolean done = new AtomicBoolean(false);
|
final AtomicBoolean done = new AtomicBoolean(false);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import de.flapdoodle.embed.mongo.config.Net;
|
||||||
import de.flapdoodle.embed.mongo.distribution.Version;
|
import de.flapdoodle.embed.mongo.distribution.Version;
|
||||||
import de.flapdoodle.embed.process.runtime.Network;
|
import de.flapdoodle.embed.process.runtime.Network;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import java.net.UnknownHostException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -36,7 +36,6 @@ public class MongoClientInstrumentationTest {
|
||||||
|
|
||||||
public static void startLocalMongo() throws Exception {
|
public static void startLocalMongo() throws Exception {
|
||||||
final MongodStarter starter = MongodStarter.getDefaultInstance();
|
final MongodStarter starter = MongodStarter.getDefaultInstance();
|
||||||
|
|
||||||
final IMongodConfig mongodConfig =
|
final IMongodConfig mongodConfig =
|
||||||
new MongodConfigBuilder()
|
new MongodConfigBuilder()
|
||||||
.version(Version.Main.PRODUCTION)
|
.version(Version.Main.PRODUCTION)
|
||||||
|
@ -62,6 +61,9 @@ public class MongoClientInstrumentationTest {
|
||||||
public static void setup() throws Exception {
|
public static void setup() throws Exception {
|
||||||
IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer);
|
IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer);
|
||||||
startLocalMongo();
|
startLocalMongo();
|
||||||
|
// Embeded Mongo uses HttpUrlConnection to download things so we have to clear traces before
|
||||||
|
// going to tests
|
||||||
|
writer.clear();
|
||||||
|
|
||||||
client = new MongoClient(MONGO_HOST, MONGO_PORT);
|
client = new MongoClient(MONGO_HOST, MONGO_PORT);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,7 @@ public class MongoClientInstrumentationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void insertOperation() throws UnknownHostException {
|
public void insertOperation() throws TimeoutException, InterruptedException {
|
||||||
final MongoDatabase db = client.getDatabase(MONGO_DB_NAME);
|
final MongoDatabase db = client.getDatabase(MONGO_DB_NAME);
|
||||||
final String collectionName = "testCollection";
|
final String collectionName = "testCollection";
|
||||||
db.createCollection(collectionName);
|
db.createCollection(collectionName);
|
||||||
|
|
|
@ -105,7 +105,9 @@ class Elasticsearch2SpringTemplateTest extends AgentTestRunner {
|
||||||
def "test elasticsearch get"() {
|
def "test elasticsearch get"() {
|
||||||
expect:
|
expect:
|
||||||
template.createIndex(indexName)
|
template.createIndex(indexName)
|
||||||
|
TEST_WRITER.waitForTraces(1)
|
||||||
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
||||||
|
TEST_WRITER.waitForTraces(2)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
||||||
|
@ -277,7 +279,10 @@ class Elasticsearch2SpringTemplateTest extends AgentTestRunner {
|
||||||
def "test results extractor"() {
|
def "test results extractor"() {
|
||||||
setup:
|
setup:
|
||||||
template.createIndex(indexName)
|
template.createIndex(indexName)
|
||||||
|
TEST_WRITER.waitForTraces(1)
|
||||||
testNode.client().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
testNode.client().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
||||||
|
TEST_WRITER.waitForTraces(2)
|
||||||
|
|
||||||
template.index(IndexQueryBuilder.newInstance()
|
template.index(IndexQueryBuilder.newInstance()
|
||||||
.withObject(new Doc(id: 1, data: "doc a"))
|
.withObject(new Doc(id: 1, data: "doc a"))
|
||||||
.withIndexName(indexName)
|
.withIndexName(indexName)
|
||||||
|
|
|
@ -105,7 +105,9 @@ class Elasticsearch2SpringTemplateTest extends AgentTestRunner {
|
||||||
def "test elasticsearch get"() {
|
def "test elasticsearch get"() {
|
||||||
expect:
|
expect:
|
||||||
template.createIndex(indexName)
|
template.createIndex(indexName)
|
||||||
|
TEST_WRITER.waitForTraces(1)
|
||||||
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
||||||
|
TEST_WRITER.waitForTraces(2)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
||||||
|
|
|
@ -125,7 +125,9 @@ class Elasticsearch53SpringTemplateTest extends AgentTestRunner {
|
||||||
def "test elasticsearch get"() {
|
def "test elasticsearch get"() {
|
||||||
expect:
|
expect:
|
||||||
template.createIndex(indexName)
|
template.createIndex(indexName)
|
||||||
|
TEST_WRITER.waitForTraces(1)
|
||||||
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
template.getClient().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
||||||
|
TEST_WRITER.waitForTraces(2)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
NativeSearchQuery query = new NativeSearchQueryBuilder()
|
||||||
|
@ -305,7 +307,10 @@ class Elasticsearch53SpringTemplateTest extends AgentTestRunner {
|
||||||
def "test results extractor"() {
|
def "test results extractor"() {
|
||||||
setup:
|
setup:
|
||||||
template.createIndex(indexName)
|
template.createIndex(indexName)
|
||||||
|
TEST_WRITER.waitForTraces(1)
|
||||||
testNode.client().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
testNode.client().admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(TIMEOUT)
|
||||||
|
TEST_WRITER.waitForTraces(2)
|
||||||
|
|
||||||
template.index(IndexQueryBuilder.newInstance()
|
template.index(IndexQueryBuilder.newInstance()
|
||||||
.withObject(new Doc(id: 1, data: "doc a"))
|
.withObject(new Doc(id: 1, data: "doc a"))
|
||||||
.withIndexName(indexName)
|
.withIndexName(indexName)
|
||||||
|
|
|
@ -17,11 +17,14 @@ import datadog.trace.bootstrap.InstrumentationContext;
|
||||||
import io.opentracing.Scope;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
|
import io.opentracing.propagation.Format;
|
||||||
|
import io.opentracing.propagation.TextMap;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
@ -35,11 +38,6 @@ public class HttpUrlConnectionInstrumentation extends Instrumenter.Default {
|
||||||
super("httpurlconnection");
|
super("httpurlconnection");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
return safeHasSuperType(named("java.net.HttpURLConnection"))
|
return safeHasSuperType(named("java.net.HttpURLConnection"))
|
||||||
|
@ -50,15 +48,16 @@ public class HttpUrlConnectionInstrumentation extends Instrumenter.Default {
|
||||||
@Override
|
@Override
|
||||||
public String[] helperClassNames() {
|
public String[] helperClassNames() {
|
||||||
return new String[] {
|
return new String[] {
|
||||||
HttpUrlConnectionInstrumentation.class.getName() + "$HttpURLState",
|
HttpUrlConnectionInstrumentation.class.getName() + "$HeadersInjectAdapter",
|
||||||
HttpUrlConnectionInstrumentation.class.getName() + "$HttpURLState$1"
|
HttpUrlConnectionInstrumentation.class.getName() + "$HttpUrlState",
|
||||||
|
HttpUrlConnectionInstrumentation.class.getName() + "$HttpUrlState$1"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> contextStore() {
|
public Map<String, String> contextStore() {
|
||||||
return Collections.singletonMap(
|
return Collections.singletonMap(
|
||||||
"java.net.HttpURLConnection", getClass().getName() + "$HttpURLState");
|
"java.net.HttpURLConnection", getClass().getName() + "$HttpUrlState");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,131 +72,170 @@ public class HttpUrlConnectionInstrumentation extends Instrumenter.Default {
|
||||||
public static class HttpUrlConnectionAdvice {
|
public static class HttpUrlConnectionAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static Scope startSpan(
|
public static HttpUrlState methodEnter(
|
||||||
@Advice.This final HttpURLConnection thiz,
|
@Advice.This final HttpURLConnection thiz,
|
||||||
@Advice.FieldValue("connected") final boolean connected,
|
@Advice.FieldValue("connected") final boolean connected) {
|
||||||
@Advice.Origin("#m") final String methodName) {
|
|
||||||
final ContextStore<HttpURLConnection, HttpURLState> contextStore =
|
|
||||||
InstrumentationContext.get(HttpURLConnection.class, HttpURLState.class);
|
|
||||||
final HttpURLState state = contextStore.putIfAbsent(thiz, HttpURLState.FACTORY);
|
|
||||||
|
|
||||||
String operationName = "http.request";
|
final ContextStore<HttpURLConnection, HttpUrlState> contextStore =
|
||||||
|
InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class);
|
||||||
|
final HttpUrlState state = contextStore.putIfAbsent(thiz, HttpUrlState.FACTORY);
|
||||||
|
|
||||||
switch (methodName) {
|
synchronized (state) {
|
||||||
case "connect":
|
/*
|
||||||
if (connected) {
|
* AgentWriter uses HttpURLConnection to report to the trace-agent. We don't want to trace
|
||||||
return null;
|
* those requests. Check after the connected test above because getRequestProperty will
|
||||||
|
* throw an exception if already connected.
|
||||||
|
*/
|
||||||
|
final boolean isTraceRequest =
|
||||||
|
Thread.currentThread().getName().equals("dd-agent-writer")
|
||||||
|
|| (!connected && thiz.getRequestProperty("Datadog-Meta-Lang") != null);
|
||||||
|
if (isTraceRequest) {
|
||||||
|
state.finish();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpURLConnection.class);
|
||||||
|
if (callDepth > 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.hasSpan() && !state.isFinished()) {
|
||||||
|
final Span span = state.startSpan(thiz);
|
||||||
|
if (!connected) {
|
||||||
|
GlobalTracer.get()
|
||||||
|
.inject(
|
||||||
|
span.context(), Format.Builtin.HTTP_HEADERS, new HeadersInjectAdapter(thiz));
|
||||||
}
|
}
|
||||||
/*
|
}
|
||||||
* Ideally, we would like to only have a single span for each of the output and input streams,
|
return state;
|
||||||
* but since headers are also sent on connect(), there wouldn't be a span to mark as parent if
|
|
||||||
* we don't create a span here.
|
|
||||||
*/
|
|
||||||
operationName += ".connect";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "getOutputStream":
|
|
||||||
if (state.calledOutputStream) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
state.calledOutputStream = true;
|
|
||||||
operationName += ".output-stream";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "getInputStream":
|
|
||||||
if (state.calledInputStream) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
state.calledInputStream = true;
|
|
||||||
operationName += ".input-stream";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* AgentWriter uses HttpURLConnection to report to the trace-agent. We don't want to trace
|
|
||||||
* those requests. Check after the connected test above because getRequestProperty will
|
|
||||||
* throw an exception if already connected.
|
|
||||||
*/
|
|
||||||
final boolean isTraceRequest =
|
|
||||||
Thread.currentThread().getName().equals("dd-agent-writer")
|
|
||||||
|| (!connected && thiz.getRequestProperty("Datadog-Meta-Lang") != null);
|
|
||||||
if (isTraceRequest) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Tracer tracer = GlobalTracer.get();
|
|
||||||
if (tracer.activeSpan() == null) {
|
|
||||||
// We don't want this as a top level span.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(HttpURLConnection.class);
|
|
||||||
if (callDepth > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Scope scope =
|
|
||||||
tracer
|
|
||||||
.buildSpan(operationName)
|
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
|
||||||
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT)
|
|
||||||
.startActive(true);
|
|
||||||
|
|
||||||
final URL url = thiz.getURL();
|
|
||||||
final Span span = scope.span();
|
|
||||||
Tags.COMPONENT.set(scope.span(), thiz.getClass().getSimpleName());
|
|
||||||
Tags.HTTP_URL.set(span, url.toString());
|
|
||||||
Tags.PEER_HOSTNAME.set(span, url.getHost());
|
|
||||||
if (url.getPort() > 0) {
|
|
||||||
Tags.PEER_PORT.set(span, url.getPort());
|
|
||||||
} else if (thiz instanceof HttpsURLConnection) {
|
|
||||||
Tags.PEER_PORT.set(span, 443);
|
|
||||||
} else {
|
|
||||||
Tags.PEER_PORT.set(span, 80);
|
|
||||||
}
|
|
||||||
Tags.HTTP_METHOD.set(span, thiz.getRequestMethod());
|
|
||||||
|
|
||||||
return scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void methodExit(
|
||||||
|
@Advice.Enter final HttpUrlState state,
|
||||||
@Advice.FieldValue("responseCode") final int responseCode,
|
@Advice.FieldValue("responseCode") final int responseCode,
|
||||||
@Advice.Enter final Scope scope,
|
@Advice.Thrown final Throwable throwable,
|
||||||
@Advice.Thrown final Throwable throwable) {
|
@Advice.Origin("#m") final String methodName) {
|
||||||
|
|
||||||
if (scope == null) {
|
if (state == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Span span = scope.span();
|
synchronized (state) {
|
||||||
if (throwable != null) {
|
if (state.hasSpan() && !state.isFinished()) {
|
||||||
Tags.ERROR.set(span, true);
|
if (throwable != null) {
|
||||||
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
|
state.finishSpan(throwable);
|
||||||
} else if (responseCode > 0) {
|
} else if ("getInputStream".equals(methodName)) {
|
||||||
/*
|
state.finishSpan(responseCode);
|
||||||
* responseCode field cache is sometimes not populated.
|
}
|
||||||
* We can't call getResponseCode() due to some unwanted side-effects
|
}
|
||||||
* (e.g. breaks getOutputStream).
|
|
||||||
*/
|
|
||||||
Tags.HTTP_STATUS.set(span, responseCode);
|
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
CallDepthThreadLocalMap.reset(HttpURLConnection.class);
|
CallDepthThreadLocalMap.reset(HttpURLConnection.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HttpURLState {
|
public static class HeadersInjectAdapter implements TextMap {
|
||||||
|
|
||||||
public static final ContextStore.Factory<HttpURLState> FACTORY =
|
private final HttpURLConnection connection;
|
||||||
new ContextStore.Factory<HttpURLState>() {
|
|
||||||
|
public HeadersInjectAdapter(final HttpURLConnection connection) {
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(final String key, final String value) {
|
||||||
|
try {
|
||||||
|
connection.setRequestProperty(key, value);
|
||||||
|
} catch (final IllegalStateException e) {
|
||||||
|
// There are cases when this can through an exception. E.g. some implementations have
|
||||||
|
// 'connecting' state. Just guard against that here, there is not much we can do at this
|
||||||
|
// point.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Map.Entry<String, String>> iterator() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This class should be used only with tracer#inject()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HttpUrlState {
|
||||||
|
|
||||||
|
public static final String OPERATION_NAME = "http.request";
|
||||||
|
public static final String COMPONENT_NAME = "http-url-connection";
|
||||||
|
|
||||||
|
public static final ContextStore.Factory<HttpUrlState> FACTORY =
|
||||||
|
new ContextStore.Factory<HttpUrlState>() {
|
||||||
@Override
|
@Override
|
||||||
public HttpURLState create() {
|
public HttpUrlState create() {
|
||||||
return new HttpURLState();
|
return new HttpUrlState();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public boolean calledOutputStream = false;
|
private volatile Span span = null;
|
||||||
public boolean calledInputStream = false;
|
private volatile boolean finished = false;
|
||||||
|
|
||||||
|
public Span startSpan(final HttpURLConnection connection) {
|
||||||
|
final Tracer.SpanBuilder builder =
|
||||||
|
GlobalTracer.get()
|
||||||
|
.buildSpan(OPERATION_NAME)
|
||||||
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
||||||
|
.withTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_CLIENT);
|
||||||
|
try (final Scope scope = builder.startActive(false)) {
|
||||||
|
span = scope.span();
|
||||||
|
final URL url = connection.getURL();
|
||||||
|
Tags.COMPONENT.set(span, COMPONENT_NAME);
|
||||||
|
Tags.HTTP_URL.set(span, url.toString());
|
||||||
|
Tags.PEER_HOSTNAME.set(span, url.getHost());
|
||||||
|
if (url.getPort() > 0) {
|
||||||
|
Tags.PEER_PORT.set(span, url.getPort());
|
||||||
|
} else if (connection instanceof HttpsURLConnection) {
|
||||||
|
Tags.PEER_PORT.set(span, 443);
|
||||||
|
} else {
|
||||||
|
Tags.PEER_PORT.set(span, 80);
|
||||||
|
}
|
||||||
|
Tags.HTTP_METHOD.set(span, connection.getRequestMethod());
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasSpan() {
|
||||||
|
return span != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished() {
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishSpan(final Throwable throwable) {
|
||||||
|
try (final Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
|
Tags.ERROR.set(span, true);
|
||||||
|
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
|
||||||
|
}
|
||||||
|
span = null;
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishSpan(final int responseCode) {
|
||||||
|
/*
|
||||||
|
* responseCode field is sometimes not populated.
|
||||||
|
* We can't call getResponseCode() due to some unwanted side-effects
|
||||||
|
* (e.g. breaks getOutputStream).
|
||||||
|
*/
|
||||||
|
if (responseCode > 0) {
|
||||||
|
try (final Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
|
Tags.HTTP_STATUS.set(span, responseCode);
|
||||||
|
span = null;
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
package datadog.trace.instrumentation.http_url_connection;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
|
||||||
import io.opentracing.Span;
|
|
||||||
import io.opentracing.Tracer;
|
|
||||||
import io.opentracing.propagation.Format;
|
|
||||||
import io.opentracing.propagation.TextMap;
|
|
||||||
import io.opentracing.util.GlobalTracer;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import sun.net.www.MessageHeader;
|
|
||||||
import sun.net.www.http.HttpClient;
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
public class SunHttpClientInstrumentation extends Instrumenter.Default {
|
|
||||||
|
|
||||||
public SunHttpClientInstrumentation() {
|
|
||||||
super("httpurlconnection");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("sun.net.www.http.HttpClient");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
SunHttpClientInstrumentation.class.getName() + "$MessageHeadersInjectAdapter"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<ElementMatcher, String> transformers() {
|
|
||||||
return Collections.<ElementMatcher, String>singletonMap(
|
|
||||||
isMethod()
|
|
||||||
.and(isPublic())
|
|
||||||
.and(named("writeRequests"))
|
|
||||||
.and(takesArgument(0, named("sun.net.www.MessageHeader")))
|
|
||||||
// exclude the delegating method:
|
|
||||||
.and(takesArguments(1).or(takesArguments(2))),
|
|
||||||
InjectAdvice.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InjectAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
|
||||||
public static void inject(
|
|
||||||
@Advice.Argument(0) final MessageHeader header, @Advice.This final HttpClient client) {
|
|
||||||
final Tracer tracer = GlobalTracer.get();
|
|
||||||
final Span span = tracer.activeSpan();
|
|
||||||
|
|
||||||
if (span != null) {
|
|
||||||
tracer.inject(
|
|
||||||
span.context(), Format.Builtin.HTTP_HEADERS, new MessageHeadersInjectAdapter(header));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MessageHeadersInjectAdapter implements TextMap {
|
|
||||||
|
|
||||||
private final MessageHeader header;
|
|
||||||
|
|
||||||
public MessageHeadersInjectAdapter(final MessageHeader header) {
|
|
||||||
this.header = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(final String key, final String value) {
|
|
||||||
header.setIfNotSet(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Map.Entry<String, String>> iterator() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This class should be used only with tracer#inject()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -31,11 +31,6 @@ public class UrlInstrumentation extends Instrumenter.Default {
|
||||||
super("urlconnection", "httpurlconnection");
|
super("urlconnection", "httpurlconnection");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean defaultEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
return is(URL.class);
|
return is(URL.class);
|
||||||
|
|
|
@ -9,11 +9,10 @@ import spock.lang.Shared
|
||||||
|
|
||||||
import static datadog.trace.agent.test.TestUtils.runUnderTrace
|
import static datadog.trace.agent.test.TestUtils.runUnderTrace
|
||||||
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
|
import static datadog.trace.agent.test.server.http.TestHttpServer.httpServer
|
||||||
|
import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.COMPONENT_NAME
|
||||||
|
import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.OPERATION_NAME
|
||||||
|
|
||||||
class HttpUrlConnectionTest extends AgentTestRunner {
|
class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
static {
|
|
||||||
System.setProperty("dd.integration.httpurlconnection.enabled", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
static final RESPONSE = "<html><body><h1>Hello test.</h1>"
|
static final RESPONSE = "<html><body><h1>Hello test.</h1>"
|
||||||
static final STATUS = 202
|
static final STATUS = 202
|
||||||
|
@ -68,11 +67,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -84,11 +83,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(2) {
|
span(2) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -144,11 +143,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -160,11 +159,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(2) {
|
span(2) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -204,11 +203,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -246,11 +245,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -297,7 +296,7 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
expect:
|
expect:
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
server.distributedRequestTrace(it, 0, TEST_WRITER[1][1])
|
server.distributedRequestTrace(it, 0, TEST_WRITER[1][1])
|
||||||
trace(1, 3) {
|
trace(1, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
operationName "someTrace"
|
operationName "someTrace"
|
||||||
parent()
|
parent()
|
||||||
|
@ -307,11 +306,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -322,21 +321,6 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(2) {
|
|
||||||
operationName "http.request.output-stream"
|
|
||||||
childOf span(0)
|
|
||||||
errored false
|
|
||||||
tags {
|
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
|
||||||
"$Tags.HTTP_METHOD.key" "POST"
|
|
||||||
"$Tags.PEER_HOSTNAME.key" "localhost"
|
|
||||||
"$Tags.PEER_PORT.key" server.address.port
|
|
||||||
defaultTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,7 +364,26 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
assert lines == [RESPONSE]
|
assert lines == [RESPONSE]
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertTraces(0) {}
|
assertTraces(1) {
|
||||||
|
trace(0, 1) {
|
||||||
|
span(0) {
|
||||||
|
operationName OPERATION_NAME
|
||||||
|
parent()
|
||||||
|
errored false
|
||||||
|
tags {
|
||||||
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
"$Tags.HTTP_METHOD.key" "GET"
|
||||||
|
"$Tags.HTTP_STATUS.key" STATUS
|
||||||
|
"$Tags.PEER_HOSTNAME.key" "localhost"
|
||||||
|
"$Tags.PEER_PORT.key" server.address.port
|
||||||
|
defaultTags()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def "rest template"() {
|
def "rest template"() {
|
||||||
|
@ -393,8 +396,8 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
server.distributedRequestTrace(it, 0, TEST_WRITER[1][2])
|
server.distributedRequestTrace(it, 0, TEST_WRITER[1][1])
|
||||||
trace(1, 4) {
|
trace(1, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
operationName "someTrace"
|
operationName "someTrace"
|
||||||
parent()
|
parent()
|
||||||
|
@ -404,11 +407,11 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored false
|
errored false
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
"$Tags.HTTP_URL.key" "$server.address"
|
||||||
|
@ -419,36 +422,6 @@ class HttpUrlConnectionTest extends AgentTestRunner {
|
||||||
defaultTags()
|
defaultTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(2) {
|
|
||||||
operationName "http.request.output-stream"
|
|
||||||
childOf span(0)
|
|
||||||
errored false
|
|
||||||
tags {
|
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
|
||||||
"$Tags.HTTP_METHOD.key" "POST"
|
|
||||||
"$Tags.PEER_HOSTNAME.key" "localhost"
|
|
||||||
"$Tags.PEER_PORT.key" server.address.port
|
|
||||||
defaultTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(3) {
|
|
||||||
operationName "http.request.connect"
|
|
||||||
childOf span(0)
|
|
||||||
errored false
|
|
||||||
tags {
|
|
||||||
"$Tags.COMPONENT.key" "HttpURLConnection"
|
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
|
||||||
"$Tags.HTTP_URL.key" "$server.address"
|
|
||||||
"$Tags.HTTP_METHOD.key" "POST"
|
|
||||||
"$Tags.PEER_HOSTNAME.key" "localhost"
|
|
||||||
"$Tags.PEER_PORT.key" server.address.port
|
|
||||||
defaultTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,14 @@ import io.opentracing.tag.Tags
|
||||||
import io.opentracing.util.GlobalTracer
|
import io.opentracing.util.GlobalTracer
|
||||||
|
|
||||||
import static datadog.trace.agent.test.TestUtils.runUnderTrace
|
import static datadog.trace.agent.test.TestUtils.runUnderTrace
|
||||||
|
import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.COMPONENT_NAME
|
||||||
|
import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectionInstrumentation.HttpUrlState.OPERATION_NAME
|
||||||
|
|
||||||
class UrlConnectionTest extends AgentTestRunner {
|
class UrlConnectionTest extends AgentTestRunner {
|
||||||
static {
|
|
||||||
System.setProperty("dd.integration.httpurlconnection.enabled", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int INVALID_PORT = TestUtils.randomOpenPort()
|
private static final int INVALID_PORT = TestUtils.randomOpenPort()
|
||||||
|
|
||||||
def "trace request with connection failure"() {
|
def "trace request with connection failure #scheme"() {
|
||||||
when:
|
when:
|
||||||
runUnderTrace("someTrace") {
|
runUnderTrace("someTrace") {
|
||||||
URLConnection connection = url.openConnection()
|
URLConnection connection = url.openConnection()
|
||||||
|
@ -41,11 +40,11 @@ class UrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
operationName "http.request.input-stream"
|
operationName OPERATION_NAME
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored true
|
errored true
|
||||||
tags {
|
tags {
|
||||||
"$Tags.COMPONENT.key" component
|
"$Tags.COMPONENT.key" COMPONENT_NAME
|
||||||
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
"$Tags.SPAN_KIND.key" Tags.SPAN_KIND_CLIENT
|
||||||
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
"$DDTags.SPAN_TYPE" DDSpanTypes.HTTP_CLIENT
|
||||||
"$Tags.HTTP_URL.key" "$url"
|
"$Tags.HTTP_URL.key" "$url"
|
||||||
|
@ -60,9 +59,9 @@ class UrlConnectionTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
where:
|
where:
|
||||||
scheme | component
|
scheme | _
|
||||||
"http" | "HttpURLConnection"
|
"http" | _
|
||||||
"https" | "DelegateHttpsURLConnection"
|
"https" | _
|
||||||
|
|
||||||
url = new URI("$scheme://localhost:$INVALID_PORT").toURL()
|
url = new URI("$scheme://localhost:$INVALID_PORT").toURL()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue