Merge pull request #126 from DataDog/tyler/ot-proposal
Changes required for supporting OT 0.31.0
This commit is contained in:
commit
55c8fddf28
|
@ -187,7 +187,7 @@ class InstrumentedClass {
|
||||||
// 2. If using the Java Agent (-javaagent;/path/to/agent.jar), do not instantiate the GlobalTracer; the Agent instantiates it for you
|
// 2. If using the Java Agent (-javaagent;/path/to/agent.jar), do not instantiate the GlobalTracer; the Agent instantiates it for you
|
||||||
Tracer tracer = io.opentracing.util.GlobalTracer.get();
|
Tracer tracer = io.opentracing.util.GlobalTracer.get();
|
||||||
|
|
||||||
Span span = tracer.buildSpan("operation-name").startActive();
|
Span span = tracer.buildSpan("operation-name").startActive(true);
|
||||||
span.setTag(DDTags.SERVICE_NAME, "my-new-service");
|
span.setTag(DDTags.SERVICE_NAME, "my-new-service");
|
||||||
|
|
||||||
// The code you're tracing
|
// The code you're tracing
|
||||||
|
@ -207,7 +207,7 @@ class InstrumentedClass {
|
||||||
void method0() {
|
void method0() {
|
||||||
Tracer tracer = io.opentracing.util.GlobalTracer.get();
|
Tracer tracer = io.opentracing.util.GlobalTracer.get();
|
||||||
|
|
||||||
try (ActiveSpan span = tracer.buildSpan("operation-name").startActive()) {
|
try (ActiveSpan span = tracer.buildSpan("operation-name").startActive(true)) {
|
||||||
span.setTag(DDTags.SERVICE_NAME, "my-new-service");
|
span.setTag(DDTags.SERVICE_NAME, "my-new-service");
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.agent.integration
|
package datadog.trace.agent.integration
|
||||||
|
|
||||||
import io.opentracing.ActiveSpan
|
import io.opentracing.Scope
|
||||||
import io.opentracing.SpanContext
|
import io.opentracing.SpanContext
|
||||||
import io.opentracing.propagation.Format
|
import io.opentracing.propagation.Format
|
||||||
import io.opentracing.propagation.TextMap
|
import io.opentracing.propagation.TextMap
|
||||||
|
@ -53,12 +53,12 @@ class TestHttpServer {
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.extract(Format.Builtin.HTTP_HEADERS, new RatpackResponseAdapter(context))
|
.extract(Format.Builtin.HTTP_HEADERS, new RatpackResponseAdapter(context))
|
||||||
ActiveSpan span =
|
Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("test-http-server")
|
.buildSpan("test-http-server")
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
.startActive()
|
.startActive(true)
|
||||||
span.deactivate()
|
scope.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
response.status(200).send(msg)
|
response.status(200).send(msg)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.agent.integration.httpclient
|
package datadog.trace.agent.integration.httpclient
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan
|
import datadog.opentracing.DDSpan
|
||||||
import datadog.opentracing.DDTracer
|
import datadog.opentracing.DDTracer
|
||||||
import datadog.trace.agent.integration.TestHttpServer
|
import datadog.trace.agent.integration.TestHttpServer
|
||||||
import datadog.trace.agent.test.TestUtils
|
import datadog.trace.agent.test.TestUtils
|
||||||
|
@ -53,18 +53,18 @@ class ApacheHttpClientTest extends Specification {
|
||||||
expect:
|
expect:
|
||||||
// one trace on the server, one trace on the client
|
// one trace on the server, one trace on the client
|
||||||
writer.size() == 2
|
writer.size() == 2
|
||||||
final List<DDBaseSpan<?>> serverTrace = writer.get(0)
|
final List<DDSpan> serverTrace = writer.get(0)
|
||||||
serverTrace.size() == 1
|
serverTrace.size() == 1
|
||||||
|
|
||||||
final List<DDBaseSpan<?>> clientTrace = writer.get(1)
|
final List<DDSpan> clientTrace = writer.get(1)
|
||||||
clientTrace.size() == 3
|
clientTrace.size() == 3
|
||||||
clientTrace.get(0).getOperationName() == "someTrace"
|
clientTrace.get(0).getOperationName() == "someTrace"
|
||||||
// our instrumentation makes 2 spans for apache-httpclient
|
// our instrumentation makes 2 spans for apache-httpclient
|
||||||
final DDBaseSpan<?> localSpan = clientTrace.get(1)
|
final DDSpan localSpan = clientTrace.get(1)
|
||||||
localSpan.getTags()[Tags.COMPONENT.getKey()] == "apache-httpclient"
|
localSpan.getTags()[Tags.COMPONENT.getKey()] == "apache-httpclient"
|
||||||
localSpan.getOperationName() == "GET"
|
localSpan.getOperationName() == "GET"
|
||||||
|
|
||||||
final DDBaseSpan<?> clientSpan = clientTrace.get(2)
|
final DDSpan clientSpan = clientTrace.get(2)
|
||||||
clientSpan.getOperationName() == "GET"
|
clientSpan.getOperationName() == "GET"
|
||||||
clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET"
|
clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET"
|
||||||
clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200
|
clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200
|
||||||
|
@ -100,15 +100,15 @@ class ApacheHttpClientTest extends Specification {
|
||||||
expect:
|
expect:
|
||||||
// only one trace (client).
|
// only one trace (client).
|
||||||
writer.size() == 1
|
writer.size() == 1
|
||||||
final List<DDBaseSpan<?>> clientTrace = writer.get(0)
|
final List<DDSpan> clientTrace = writer.get(0)
|
||||||
clientTrace.size() == 3
|
clientTrace.size() == 3
|
||||||
clientTrace.get(0).getOperationName() == "someTrace"
|
clientTrace.get(0).getOperationName() == "someTrace"
|
||||||
// our instrumentation makes 2 spans for apache-httpclient
|
// our instrumentation makes 2 spans for apache-httpclient
|
||||||
final DDBaseSpan<?> localSpan = clientTrace.get(1)
|
final DDSpan localSpan = clientTrace.get(1)
|
||||||
localSpan.getTags()[Tags.COMPONENT.getKey()] == "apache-httpclient"
|
localSpan.getTags()[Tags.COMPONENT.getKey()] == "apache-httpclient"
|
||||||
localSpan.getOperationName() == "GET"
|
localSpan.getOperationName() == "GET"
|
||||||
|
|
||||||
final DDBaseSpan<?> clientSpan = clientTrace.get(2)
|
final DDSpan clientSpan = clientTrace.get(2)
|
||||||
clientSpan.getOperationName() == "GET"
|
clientSpan.getOperationName() == "GET"
|
||||||
clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET"
|
clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET"
|
||||||
clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200
|
clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.agent.integration.servlet
|
package datadog.trace.agent.integration.servlet
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan
|
import datadog.opentracing.DDSpan
|
||||||
import datadog.opentracing.DDTracer
|
import datadog.opentracing.DDTracer
|
||||||
import datadog.trace.common.writer.ListWriter
|
import datadog.trace.common.writer.ListWriter
|
||||||
import io.opentracing.util.GlobalTracer
|
import io.opentracing.util.GlobalTracer
|
||||||
|
@ -43,7 +43,7 @@ class JettyServletTest extends Specification {
|
||||||
|
|
||||||
ListWriter writer = new ListWriter() {
|
ListWriter writer = new ListWriter() {
|
||||||
@Override
|
@Override
|
||||||
void write(final List<DDBaseSpan<?>> trace) {
|
void write(final List<DDSpan> trace) {
|
||||||
add(trace)
|
add(trace)
|
||||||
JettyServletTest.latch.countDown()
|
JettyServletTest.latch.countDown()
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ class TomcatServletTest extends Specification {
|
||||||
}
|
}
|
||||||
appContext = tomcatServer.addWebapp("", applicationDir.getAbsolutePath())
|
appContext = tomcatServer.addWebapp("", applicationDir.getAbsolutePath())
|
||||||
// Speed up startup by disabling jar scanning:
|
// Speed up startup by disabling jar scanning:
|
||||||
appContext.getJarScanner().setJarScanFilter(new JarScanFilter(){
|
appContext.getJarScanner().setJarScanFilter(new JarScanFilter() {
|
||||||
@Override
|
@Override
|
||||||
boolean check(JarScanType jarScanType, String jarName) {
|
boolean check(JarScanType jarScanType, String jarName) {
|
||||||
return false
|
return false
|
||||||
|
@ -147,9 +147,9 @@ class TomcatServletTest extends Specification {
|
||||||
span.context().tags.size() == 11
|
span.context().tags.size() == 11
|
||||||
|
|
||||||
where:
|
where:
|
||||||
path | expectedResponse
|
path | expectedResponse
|
||||||
//"async" | "Hello Async" // FIXME: I can't seem get the async error handler to trigger
|
//"async" | "Hello Async" // FIXME: I can't seem get the async error handler to trigger
|
||||||
"sync" | "Hello Sync"
|
"sync" | "Hello Sync"
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int randomOpenPort() {
|
private static int randomOpenPort() {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package datadog.trace.agent.instrumentation.annotation;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.opentracing.DDTracer;
|
import datadog.opentracing.DDTracer;
|
||||||
import datadog.opentracing.decorators.ErrorFlag;
|
import datadog.opentracing.decorators.ErrorFlag;
|
||||||
import datadog.trace.agent.test.SayTracedHello;
|
import datadog.trace.agent.test.SayTracedHello;
|
||||||
|
@ -73,7 +73,7 @@ public class TraceAnnotationsTest {
|
||||||
final StringWriter errorString = new StringWriter();
|
final StringWriter errorString = new StringWriter();
|
||||||
error.printStackTrace(new PrintWriter(errorString));
|
error.printStackTrace(new PrintWriter(errorString));
|
||||||
|
|
||||||
final DDBaseSpan<?> span = writer.firstTrace().get(0);
|
final DDSpan span = writer.firstTrace().get(0);
|
||||||
assertThat(span.getOperationName()).isEqualTo("ERROR");
|
assertThat(span.getOperationName()).isEqualTo("ERROR");
|
||||||
assertThat(span.getTags().get("error")).isEqualTo(true);
|
assertThat(span.getTags().get("error")).isEqualTo(true);
|
||||||
assertThat(span.getTags().get("error.msg")).isEqualTo(error.getMessage());
|
assertThat(span.getTags().get("error.msg")).isEqualTo(error.getMessage());
|
||||||
|
|
|
@ -8,7 +8,7 @@ import com.mongodb.async.SingleResultCallback;
|
||||||
import com.mongodb.async.client.MongoClient;
|
import com.mongodb.async.client.MongoClient;
|
||||||
import com.mongodb.async.client.MongoClients;
|
import com.mongodb.async.client.MongoClients;
|
||||||
import com.mongodb.async.client.MongoDatabase;
|
import com.mongodb.async.client.MongoDatabase;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.opentracing.DDTracer;
|
import datadog.opentracing.DDTracer;
|
||||||
import datadog.trace.agent.test.TestUtils;
|
import datadog.trace.agent.test.TestUtils;
|
||||||
import datadog.trace.common.writer.ListWriter;
|
import datadog.trace.common.writer.ListWriter;
|
||||||
|
@ -103,7 +103,7 @@ public class MongoAsyncClientInstrumentationTest {
|
||||||
|
|
||||||
final String createCollectionQuery =
|
final String createCollectionQuery =
|
||||||
"{ \"create\" : \"asyncCollection\", \"autoIndexId\" : \"?\", \"capped\" : \"?\" }";
|
"{ \"create\" : \"asyncCollection\", \"autoIndexId\" : \"?\", \"capped\" : \"?\" }";
|
||||||
final DDBaseSpan<?> trace0 = writer.get(0).get(0);
|
final DDSpan trace0 = writer.get(0).get(0);
|
||||||
Assert.assertEquals("mongo.query", trace0.getOperationName());
|
Assert.assertEquals("mongo.query", trace0.getOperationName());
|
||||||
Assert.assertEquals(createCollectionQuery, trace0.getResourceName());
|
Assert.assertEquals(createCollectionQuery, trace0.getResourceName());
|
||||||
Assert.assertEquals("mongodb", trace0.getType());
|
Assert.assertEquals("mongodb", trace0.getType());
|
||||||
|
|
|
@ -3,7 +3,7 @@ package datadog.trace.agent.integration;
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
import com.mongodb.client.MongoCollection;
|
import com.mongodb.client.MongoCollection;
|
||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.opentracing.DDTracer;
|
import datadog.opentracing.DDTracer;
|
||||||
import datadog.trace.agent.test.TestUtils;
|
import datadog.trace.agent.test.TestUtils;
|
||||||
import datadog.trace.common.writer.ListWriter;
|
import datadog.trace.common.writer.ListWriter;
|
||||||
|
@ -100,7 +100,7 @@ public class MongoClientInstrumentationTest {
|
||||||
|
|
||||||
final String createCollectionQuery =
|
final String createCollectionQuery =
|
||||||
"{ \"create\" : \"testCollection\", \"autoIndexId\" : \"?\", \"capped\" : \"?\" }";
|
"{ \"create\" : \"testCollection\", \"autoIndexId\" : \"?\", \"capped\" : \"?\" }";
|
||||||
final DDBaseSpan<?> trace0 = writer.get(0).get(0);
|
final DDSpan trace0 = writer.get(0).get(0);
|
||||||
Assert.assertEquals("mongo.query", trace0.getOperationName());
|
Assert.assertEquals("mongo.query", trace0.getOperationName());
|
||||||
Assert.assertEquals(createCollectionQuery, trace0.getResourceName());
|
Assert.assertEquals(createCollectionQuery, trace0.getResourceName());
|
||||||
Assert.assertEquals("mongodb", trace0.getType());
|
Assert.assertEquals("mongodb", trace0.getType());
|
||||||
|
|
|
@ -9,20 +9,23 @@ public class SayTracedHello {
|
||||||
|
|
||||||
@Trace
|
@Trace
|
||||||
public static String sayHello() {
|
public static String sayHello() {
|
||||||
new StringTag(DDTags.SERVICE_NAME).set(GlobalTracer.get().activeSpan(), "test");
|
new StringTag(DDTags.SERVICE_NAME)
|
||||||
|
.set(GlobalTracer.get().scopeManager().active().span(), "test");
|
||||||
return "hello!";
|
return "hello!";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Trace(operationName = "SAY_HA")
|
@Trace(operationName = "SAY_HA")
|
||||||
public static String sayHA() {
|
public static String sayHA() {
|
||||||
new StringTag(DDTags.SERVICE_NAME).set(GlobalTracer.get().activeSpan(), "test");
|
new StringTag(DDTags.SERVICE_NAME)
|
||||||
new StringTag(DDTags.SPAN_TYPE).set(GlobalTracer.get().activeSpan(), "DB");
|
.set(GlobalTracer.get().scopeManager().active().span(), "test");
|
||||||
|
new StringTag(DDTags.SPAN_TYPE).set(GlobalTracer.get().scopeManager().active().span(), "DB");
|
||||||
return "HA!!";
|
return "HA!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Trace(operationName = "NEW_TRACE")
|
@Trace(operationName = "NEW_TRACE")
|
||||||
public static String sayHELLOsayHA() {
|
public static String sayHELLOsayHA() {
|
||||||
new StringTag(DDTags.SERVICE_NAME).set(GlobalTracer.get().activeSpan(), "test2");
|
new StringTag(DDTags.SERVICE_NAME)
|
||||||
|
.set(GlobalTracer.get().scopeManager().active().span(), "test2");
|
||||||
return sayHello() + sayHA();
|
return sayHello() + sayHA();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package datadog.trace.instrumentation.apachehttpclient;
|
package datadog.trace.instrumentation.apachehttpclient;
|
||||||
|
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.propagation.TextMap;
|
import io.opentracing.propagation.TextMap;
|
||||||
|
@ -48,10 +49,10 @@ public class DDTracingClientExec implements ClientExecChain {
|
||||||
private final Tracer tracer;
|
private final Tracer tracer;
|
||||||
|
|
||||||
public DDTracingClientExec(
|
public DDTracingClientExec(
|
||||||
ClientExecChain clientExecChain,
|
final ClientExecChain clientExecChain,
|
||||||
RedirectStrategy redirectStrategy,
|
final RedirectStrategy redirectStrategy,
|
||||||
boolean redirectHandlingDisabled,
|
final boolean redirectHandlingDisabled,
|
||||||
Tracer tracer) {
|
final Tracer tracer) {
|
||||||
this.requestExecutor = clientExecChain;
|
this.requestExecutor = clientExecChain;
|
||||||
this.redirectStrategy = redirectStrategy;
|
this.redirectStrategy = redirectStrategy;
|
||||||
this.redirectHandlingDisabled = redirectHandlingDisabled;
|
this.redirectHandlingDisabled = redirectHandlingDisabled;
|
||||||
|
@ -60,30 +61,30 @@ public class DDTracingClientExec implements ClientExecChain {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CloseableHttpResponse execute(
|
public CloseableHttpResponse execute(
|
||||||
HttpRoute route,
|
final HttpRoute route,
|
||||||
HttpRequestWrapper request,
|
final HttpRequestWrapper request,
|
||||||
HttpClientContext clientContext,
|
final HttpClientContext clientContext,
|
||||||
HttpExecutionAware execAware)
|
final HttpExecutionAware execAware)
|
||||||
throws IOException, HttpException {
|
throws IOException, HttpException {
|
||||||
|
|
||||||
ActiveSpan localSpan = clientContext.getAttribute(ACTIVE_SPAN, ActiveSpan.class);
|
Scope localScope = clientContext.getAttribute(ACTIVE_SPAN, Scope.class);
|
||||||
CloseableHttpResponse response = null;
|
CloseableHttpResponse response = null;
|
||||||
try {
|
try {
|
||||||
if (localSpan == null) {
|
if (localScope == null) {
|
||||||
localSpan = createLocalSpan(request, clientContext);
|
localScope = createLocalScope(request, clientContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (response = createNetworkSpan(localSpan, route, request, clientContext, execAware));
|
return (response = createNetworkSpan(localScope, route, request, clientContext, execAware));
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
localSpan.deactivate();
|
localScope.close();
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
/**
|
/**
|
||||||
* This exec runs after {@link org.apache.http.impl.execchain.RedirectExec} which loops
|
* This exec runs after {@link org.apache.http.impl.execchain.RedirectExec} which loops
|
||||||
* until there is no redirect or reaches max redirect count. {@link RedirectStrategy} is
|
* until there is no redirect or reaches max redirect count. {@link RedirectStrategy} is
|
||||||
* used to decide whether localSpan should be finished or not. If there is a redirect
|
* used to decide whether localScope should be finished or not. If there is a redirect
|
||||||
* localSpan is not finished and redirect is logged.
|
* localScope is not finished and redirect is logged.
|
||||||
*/
|
*/
|
||||||
Integer redirectCount = clientContext.getAttribute(REDIRECT_COUNT, Integer.class);
|
Integer redirectCount = clientContext.getAttribute(REDIRECT_COUNT, Integer.class);
|
||||||
if (!redirectHandlingDisabled
|
if (!redirectHandlingDisabled
|
||||||
|
@ -92,37 +93,40 @@ public class DDTracingClientExec implements ClientExecChain {
|
||||||
&& ++redirectCount < clientContext.getRequestConfig().getMaxRedirects()) {
|
&& ++redirectCount < clientContext.getRequestConfig().getMaxRedirects()) {
|
||||||
clientContext.setAttribute(REDIRECT_COUNT, redirectCount);
|
clientContext.setAttribute(REDIRECT_COUNT, redirectCount);
|
||||||
} else {
|
} else {
|
||||||
localSpan.deactivate();
|
localScope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActiveSpan createLocalSpan(HttpRequest httpRequest, HttpClientContext clientContext) {
|
private Scope createLocalScope(
|
||||||
Tracer.SpanBuilder spanBuilder =
|
final HttpRequest httpRequest, final HttpClientContext clientContext) {
|
||||||
|
final Tracer.SpanBuilder spanBuilder =
|
||||||
tracer
|
tracer
|
||||||
.buildSpan(httpRequest.getRequestLine().getMethod())
|
.buildSpan(httpRequest.getRequestLine().getMethod())
|
||||||
.withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME);
|
.withTag(Tags.COMPONENT.getKey(), COMPONENT_NAME);
|
||||||
|
|
||||||
ActiveSpan localSpan = spanBuilder.startActive();
|
final Scope scope = spanBuilder.startActive(true);
|
||||||
clientContext.setAttribute(ACTIVE_SPAN, localSpan);
|
clientContext.setAttribute(ACTIVE_SPAN, scope);
|
||||||
clientContext.setAttribute(REDIRECT_COUNT, 0);
|
clientContext.setAttribute(REDIRECT_COUNT, 0);
|
||||||
return localSpan;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CloseableHttpResponse createNetworkSpan(
|
private CloseableHttpResponse createNetworkSpan(
|
||||||
ActiveSpan parentSpan,
|
final Scope parentScope,
|
||||||
HttpRoute route,
|
final HttpRoute route,
|
||||||
HttpRequestWrapper request,
|
final HttpRequestWrapper request,
|
||||||
HttpClientContext clientContext,
|
final HttpClientContext clientContext,
|
||||||
HttpExecutionAware execAware)
|
final HttpExecutionAware execAware)
|
||||||
throws IOException, HttpException {
|
throws IOException, HttpException {
|
||||||
ActiveSpan networkSpan =
|
final Scope networkScope =
|
||||||
tracer
|
tracer
|
||||||
.buildSpan(request.getMethod())
|
.buildSpan(request.getMethod())
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT)
|
||||||
.asChildOf(parentSpan)
|
.asChildOf(parentScope.span())
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
|
final Span networkSpan = networkScope.span();
|
||||||
tracer.inject(
|
tracer.inject(
|
||||||
networkSpan.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersInjectAdapter(request));
|
networkSpan.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersInjectAdapter(request));
|
||||||
|
|
||||||
|
@ -148,20 +152,20 @@ public class DDTracingClientExec implements ClientExecChain {
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
networkSpan.deactivate();
|
networkScope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HttpHeadersInjectAdapter implements TextMap {
|
public static class HttpHeadersInjectAdapter implements TextMap {
|
||||||
|
|
||||||
private HttpRequest httpRequest;
|
private final HttpRequest httpRequest;
|
||||||
|
|
||||||
public HttpHeadersInjectAdapter(HttpRequest httpRequest) {
|
public HttpHeadersInjectAdapter(final HttpRequest httpRequest) {
|
||||||
this.httpRequest = httpRequest;
|
this.httpRequest = httpRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(String key, String value) {
|
public void put(final String key, final String value) {
|
||||||
httpRequest.addHeader(key, value);
|
httpRequest.addHeader(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
|
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
|
||||||
compile('io.opentracing.contrib:opentracing-aws-sdk:0.0.2') {
|
compile('io.opentracing.contrib:opentracing-aws-sdk:0.0.3-RC1') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0'
|
compileOnly group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0'
|
||||||
compile('io.opentracing.contrib:opentracing-cassandra-driver:0.0.2') {
|
compile('io.opentracing.contrib:opentracing-cassandra-driver:0.0.3-RC1') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import com.datastax.driver.core.Cluster
|
import com.datastax.driver.core.Cluster
|
||||||
import com.datastax.driver.core.Session
|
import com.datastax.driver.core.Session
|
||||||
import datadog.opentracing.DDBaseSpan
|
import datadog.opentracing.DDSpan
|
||||||
import datadog.opentracing.DDTracer
|
import datadog.opentracing.DDTracer
|
||||||
import datadog.trace.agent.test.AgentTestRunner
|
import datadog.trace.agent.test.AgentTestRunner
|
||||||
import io.opentracing.tag.Tags
|
import io.opentracing.tag.Tags
|
||||||
|
@ -31,7 +31,7 @@ class CassandraClientTest extends AgentTestRunner {
|
||||||
expect:
|
expect:
|
||||||
session.getClass().getName().endsWith("contrib.cassandra.TracingSession")
|
session.getClass().getName().endsWith("contrib.cassandra.TracingSession")
|
||||||
TEST_WRITER.size() == 5
|
TEST_WRITER.size() == 5
|
||||||
final DDBaseSpan<?> selectTrace = TEST_WRITER.get(TEST_WRITER.size() - 1).get(0)
|
final DDSpan selectTrace = TEST_WRITER.get(TEST_WRITER.size() - 1).get(0)
|
||||||
|
|
||||||
selectTrace.getServiceName() == DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME
|
selectTrace.getServiceName() == DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME
|
||||||
selectTrace.getOperationName() == "execute"
|
selectTrace.getOperationName() == "execute"
|
||||||
|
@ -67,7 +67,7 @@ class CassandraClientTest extends AgentTestRunner {
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
session.getClass().getName().endsWith("contrib.cassandra.TracingSession")
|
session.getClass().getName().endsWith("contrib.cassandra.TracingSession")
|
||||||
final DDBaseSpan<?> selectTrace = TEST_WRITER.get(TEST_WRITER.size() - 1).get(0)
|
final DDSpan selectTrace = TEST_WRITER.get(TEST_WRITER.size() - 1).get(0)
|
||||||
|
|
||||||
selectTrace.getServiceName() == DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME
|
selectTrace.getServiceName() == DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME
|
||||||
selectTrace.getOperationName() == "execute"
|
selectTrace.getOperationName() == "execute"
|
||||||
|
|
|
@ -12,8 +12,9 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.NoopActiveSpanSource;
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.noop.NoopScopeManager;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
@ -41,14 +42,14 @@ public final class PreparedStatementInstrumentation implements Instrumenter {
|
||||||
public static class PreparedStatementAdvice {
|
public static class PreparedStatementAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.This final PreparedStatement statement) {
|
public static Scope startSpan(@Advice.This final PreparedStatement statement) {
|
||||||
final String sql = ConnectionInstrumentation.preparedStatements.get(statement);
|
final String sql = ConnectionInstrumentation.preparedStatements.get(statement);
|
||||||
final Connection connection;
|
final Connection connection;
|
||||||
try {
|
try {
|
||||||
connection = statement.getConnection();
|
connection = statement.getConnection();
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
// Had some problem getting the connection.
|
// Had some problem getting the connection.
|
||||||
return NoopActiveSpanSource.NoopActiveSpan.INSTANCE;
|
return NoopScopeManager.NoopScope.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionInstrumentation.DBInfo dbInfo =
|
ConnectionInstrumentation.DBInfo dbInfo =
|
||||||
|
@ -56,9 +57,10 @@ public final class PreparedStatementInstrumentation implements Instrumenter {
|
||||||
if (dbInfo == null) {
|
if (dbInfo == null) {
|
||||||
dbInfo = ConnectionInstrumentation.DBInfo.UNKNOWN;
|
dbInfo = ConnectionInstrumentation.DBInfo.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
final Scope scope =
|
||||||
|
GlobalTracer.get().buildSpan(dbInfo.getType() + ".query").startActive(true);
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Span span = scope.span();
|
||||||
GlobalTracer.get().buildSpan(dbInfo.getType() + ".query").startActive();
|
|
||||||
Tags.DB_TYPE.set(span, dbInfo.getType());
|
Tags.DB_TYPE.set(span, dbInfo.getType());
|
||||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||||
Tags.COMPONENT.set(span, "java-jdbc-prepared_statement");
|
Tags.COMPONENT.set(span, "java-jdbc-prepared_statement");
|
||||||
|
@ -72,17 +74,18 @@ public final class PreparedStatementInstrumentation implements Instrumenter {
|
||||||
if (dbInfo.getUser() != null) {
|
if (dbInfo.getUser() != null) {
|
||||||
Tags.DB_USER.set(span, dbInfo.getUser());
|
Tags.DB_USER.set(span, dbInfo.getUser());
|
||||||
}
|
}
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan activeSpan, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Tags.ERROR.set(activeSpan, true);
|
final Span span = scope.span();
|
||||||
activeSpan.log(Collections.singletonMap("error.object", throwable));
|
Tags.ERROR.set(span, true);
|
||||||
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
activeSpan.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.NoopActiveSpanSource;
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.noop.NoopScopeManager;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
@ -40,14 +41,14 @@ public final class StatementInstrumentation implements Instrumenter {
|
||||||
public static class StatementAdvice {
|
public static class StatementAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final String sql, @Advice.This final Statement statement) {
|
@Advice.Argument(0) final String sql, @Advice.This final Statement statement) {
|
||||||
final Connection connection;
|
final Connection connection;
|
||||||
try {
|
try {
|
||||||
connection = statement.getConnection();
|
connection = statement.getConnection();
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
// Had some problem getting the connection.
|
// Had some problem getting the connection.
|
||||||
return NoopActiveSpanSource.NoopActiveSpan.INSTANCE;
|
return NoopScopeManager.NoopScope.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionInstrumentation.DBInfo dbInfo =
|
ConnectionInstrumentation.DBInfo dbInfo =
|
||||||
|
@ -56,8 +57,11 @@ public final class StatementInstrumentation implements Instrumenter {
|
||||||
dbInfo = ConnectionInstrumentation.DBInfo.UNKNOWN;
|
dbInfo = ConnectionInstrumentation.DBInfo.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get().buildSpan(dbInfo.getType() + ".query").startActive();
|
GlobalTracer.get().buildSpan(dbInfo.getType() + ".query").startActive(true);
|
||||||
|
|
||||||
|
final Span span = scope.span();
|
||||||
|
|
||||||
Tags.DB_TYPE.set(span, dbInfo.getType());
|
Tags.DB_TYPE.set(span, dbInfo.getType());
|
||||||
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
|
||||||
Tags.COMPONENT.set(span, "java-jdbc-statement");
|
Tags.COMPONENT.set(span, "java-jdbc-statement");
|
||||||
|
@ -71,17 +75,18 @@ public final class StatementInstrumentation implements Instrumenter {
|
||||||
if (dbInfo.getUser() != null) {
|
if (dbInfo.getUser() != null) {
|
||||||
Tags.DB_USER.set(span, dbInfo.getUser());
|
Tags.DB_USER.set(span, dbInfo.getUser());
|
||||||
}
|
}
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan activeSpan, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Tags.ERROR.set(activeSpan, true);
|
final Span span = scope.span();
|
||||||
activeSpan.log(Collections.singletonMap("error.object", throwable));
|
Tags.ERROR.set(span, true);
|
||||||
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
activeSpan.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
|
@ -69,7 +70,7 @@ public final class JMS1MessageConsumerInstrumentation implements Instrumenter {
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.consume")
|
.buildSpan("jms.consume")
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
|
@ -78,14 +79,15 @@ public final class JMS1MessageConsumerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
||||||
.withTag("span.origin.type", consumer.getClass().getName())
|
.withTag("span.origin.type", consumer.getClass().getName())
|
||||||
.withStartTimestamp(TimeUnit.MILLISECONDS.toMicros(startTime))
|
.withStartTimestamp(TimeUnit.MILLISECONDS.toMicros(startTime))
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
final Span span = scope.span();
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.setTag(DDTags.RESOURCE_NAME, "Consumed from " + toResourceName(message, null));
|
span.setTag(DDTags.RESOURCE_NAME, "Consumed from " + toResourceName(message, null));
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
|
@ -48,36 +49,34 @@ public final class JMS1MessageListenerInstrumentation implements Instrumenter {
|
||||||
public static class MessageListenerAdvice {
|
public static class MessageListenerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Message message, @Advice.This final MessageListener listener) {
|
@Advice.Argument(0) final Message message, @Advice.This final MessageListener listener) {
|
||||||
|
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
final ActiveSpan span =
|
return GlobalTracer.get()
|
||||||
GlobalTracer.get()
|
.buildSpan("jms.onMessage")
|
||||||
.buildSpan("jms.onMessage")
|
.asChildOf(extractedContext)
|
||||||
.asChildOf(extractedContext)
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.RESOURCE_NAME, "Received from " + toResourceName(message, null))
|
||||||
.withTag(DDTags.RESOURCE_NAME, "Received from " + toResourceName(message, null))
|
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
.withTag("span.origin.type", listener.getClass().getName())
|
||||||
.withTag("span.origin.type", listener.getClass().getName())
|
.startActive(true);
|
||||||
.startActive();
|
|
||||||
|
|
||||||
return span;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
@ -53,7 +54,7 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
||||||
public static class ProducerAdvice {
|
public static class ProducerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Message message, @Advice.This final MessageProducer producer) {
|
@Advice.Argument(0) final Message message, @Advice.This final MessageProducer producer) {
|
||||||
Destination defaultDestination;
|
Destination defaultDestination;
|
||||||
try {
|
try {
|
||||||
|
@ -61,7 +62,7 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
||||||
} catch (final JMSException e) {
|
} catch (final JMSException e) {
|
||||||
defaultDestination = null;
|
defaultDestination = null;
|
||||||
}
|
}
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.produce")
|
.buildSpan("jms.produce")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
|
@ -71,24 +72,26 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
||||||
.withTag("span.origin.type", producer.getClass().getName())
|
.withTag("span.origin.type", producer.getClass().getName())
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.inject(span.context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
.inject(
|
||||||
|
scope.span().context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,11 +99,11 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
||||||
public static class ProducerWithDestinationAdvice {
|
public static class ProducerWithDestinationAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Destination destination,
|
@Advice.Argument(0) final Destination destination,
|
||||||
@Advice.Argument(1) final Message message,
|
@Advice.Argument(1) final Message message,
|
||||||
@Advice.This final MessageProducer producer) {
|
@Advice.This final MessageProducer producer) {
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.produce")
|
.buildSpan("jms.produce")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
|
@ -108,23 +111,26 @@ public final class JMS1MessageProducerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
.withTag(Tags.COMPONENT.getKey(), "jms1")
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
||||||
.withTag("span.origin.type", producer.getClass().getName())
|
.withTag("span.origin.type", producer.getClass().getName())
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.inject(span.context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
.inject(
|
||||||
return span;
|
scope.span().context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
|
@ -69,7 +70,7 @@ public final class JMS2MessageConsumerInstrumentation implements Instrumenter {
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.consume")
|
.buildSpan("jms.consume")
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
|
@ -78,14 +79,16 @@ public final class JMS2MessageConsumerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
||||||
.withTag("span.origin.type", consumer.getClass().getName())
|
.withTag("span.origin.type", consumer.getClass().getName())
|
||||||
.withStartTimestamp(TimeUnit.MILLISECONDS.toMicros(startTime))
|
.withStartTimestamp(TimeUnit.MILLISECONDS.toMicros(startTime))
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
|
final Span span = scope.span();
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.setTag(DDTags.RESOURCE_NAME, "Consumed from " + toResourceName(message, null));
|
span.setTag(DDTags.RESOURCE_NAME, "Consumed from " + toResourceName(message, null));
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
|
@ -48,36 +49,34 @@ public final class JMS2MessageListenerInstrumentation implements Instrumenter {
|
||||||
public static class MessageListenerAdvice {
|
public static class MessageListenerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Message message, @Advice.This final MessageListener listener) {
|
@Advice.Argument(0) final Message message, @Advice.This final MessageListener listener) {
|
||||||
|
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
final ActiveSpan span =
|
return GlobalTracer.get()
|
||||||
GlobalTracer.get()
|
.buildSpan("jms.onMessage")
|
||||||
.buildSpan("jms.onMessage")
|
.asChildOf(extractedContext)
|
||||||
.asChildOf(extractedContext)
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.RESOURCE_NAME, "Received from " + toResourceName(message, null))
|
||||||
.withTag(DDTags.RESOURCE_NAME, "Received from " + toResourceName(message, null))
|
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER)
|
.withTag("span.origin.type", listener.getClass().getName())
|
||||||
.withTag("span.origin.type", listener.getClass().getName())
|
.startActive(true);
|
||||||
.startActive();
|
|
||||||
|
|
||||||
return span;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
import datadog.trace.instrumentation.jms.util.MessagePropertyTextMap;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
@ -53,7 +54,7 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
||||||
public static class ProducerAdvice {
|
public static class ProducerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Message message, @Advice.This final MessageProducer producer) {
|
@Advice.Argument(0) final Message message, @Advice.This final MessageProducer producer) {
|
||||||
Destination defaultDestination;
|
Destination defaultDestination;
|
||||||
try {
|
try {
|
||||||
|
@ -61,7 +62,7 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
||||||
} catch (final JMSException e) {
|
} catch (final JMSException e) {
|
||||||
defaultDestination = null;
|
defaultDestination = null;
|
||||||
}
|
}
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.produce")
|
.buildSpan("jms.produce")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
|
@ -71,24 +72,26 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
||||||
.withTag("span.origin.type", producer.getClass().getName())
|
.withTag("span.origin.type", producer.getClass().getName())
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.inject(span.context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
.inject(
|
||||||
|
scope.span().context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,11 +99,11 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
||||||
public static class ProducerWithDestinationAdvice {
|
public static class ProducerWithDestinationAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(
|
public static Scope startSpan(
|
||||||
@Advice.Argument(0) final Destination destination,
|
@Advice.Argument(0) final Destination destination,
|
||||||
@Advice.Argument(1) final Message message,
|
@Advice.Argument(1) final Message message,
|
||||||
@Advice.This final MessageProducer producer) {
|
@Advice.This final MessageProducer producer) {
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan("jms.produce")
|
.buildSpan("jms.produce")
|
||||||
.withTag(DDTags.SERVICE_NAME, "jms")
|
.withTag(DDTags.SERVICE_NAME, "jms")
|
||||||
|
@ -108,23 +111,25 @@ public final class JMS2MessageProducerInstrumentation implements Instrumenter {
|
||||||
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
.withTag(Tags.COMPONENT.getKey(), "jms2")
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER)
|
||||||
.withTag("span.origin.type", producer.getClass().getName())
|
.withTag("span.origin.type", producer.getClass().getName())
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.inject(span.context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
.inject(
|
||||||
return span;
|
scope.span().context(), Format.Builtin.TEXT_MAP, new MessagePropertyTextMap(message));
|
||||||
|
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 stopSpan(
|
||||||
@Advice.Enter final ActiveSpan span, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
Tags.ERROR.set(span, Boolean.TRUE);
|
Tags.ERROR.set(span, Boolean.TRUE);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.0.0'
|
compileOnly group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.0.0'
|
||||||
compile('io.opentracing.contrib:opentracing-okhttp3:0.0.5') {
|
compile('io.opentracing.contrib:opentracing-okhttp3:0.1.0-RC1') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,7 @@ public class OkHttp3Instrumentation implements Instrumenter {
|
||||||
"io.opentracing.contrib.okhttp3.RequestBuilderInjectAdapter",
|
"io.opentracing.contrib.okhttp3.RequestBuilderInjectAdapter",
|
||||||
"io.opentracing.contrib.okhttp3.TracingCallFactory",
|
"io.opentracing.contrib.okhttp3.TracingCallFactory",
|
||||||
"io.opentracing.contrib.okhttp3.TracingCallFactory$NetworkInterceptor",
|
"io.opentracing.contrib.okhttp3.TracingCallFactory$NetworkInterceptor",
|
||||||
"io.opentracing.contrib.okhttp3.TracingCallFactory$1",
|
"io.opentracing.contrib.okhttp3.TracingCallFactory$1"))
|
||||||
"io.opentracing.contrib.okhttp3.concurrent.TracingExecutorService",
|
|
||||||
"io.opentracing.contrib.okhttp3.concurrent.TracedCallable",
|
|
||||||
"io.opentracing.contrib.okhttp3.concurrent.TracedRunnable"))
|
|
||||||
.transform(
|
.transform(
|
||||||
DDAdvice.create()
|
DDAdvice.create()
|
||||||
.advice(
|
.advice(
|
||||||
|
|
|
@ -14,7 +14,7 @@ apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'javax.servlet', name: 'servlet-api', version: '2.3'
|
compileOnly group: 'javax.servlet', name: 'servlet-api', version: '2.3'
|
||||||
compile('io.opentracing.contrib:opentracing-web-servlet-filter:0.0.9') {
|
compile('io.opentracing.contrib:opentracing-web-servlet-filter:0.1.0-RC1') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.HelperInjector;
|
import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
||||||
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
||||||
|
@ -62,8 +63,9 @@ public final class FilterChain2Instrumentation implements Instrumenter {
|
||||||
public static class FilterChain2Advice {
|
public static class FilterChain2Advice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.Argument(0) final ServletRequest req) {
|
public static Scope startSpan(@Advice.Argument(0) final ServletRequest req) {
|
||||||
if (GlobalTracer.get().activeSpan() != null || !(req instanceof HttpServletRequest)) {
|
if (GlobalTracer.get().scopeManager().active() != null
|
||||||
|
|| !(req instanceof HttpServletRequest)) {
|
||||||
// doFilter is called by each filter. We only want to time outer-most.
|
// doFilter is called by each filter. We only want to time outer-most.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -74,26 +76,27 @@ public final class FilterChain2Instrumentation implements Instrumenter {
|
||||||
Format.Builtin.HTTP_HEADERS,
|
Format.Builtin.HTTP_HEADERS,
|
||||||
new HttpServletRequestExtractAdapter((HttpServletRequest) req));
|
new HttpServletRequestExtractAdapter((HttpServletRequest) req));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan(FILTER_CHAIN_OPERATION_NAME)
|
.buildSpan(FILTER_CHAIN_OPERATION_NAME)
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest((HttpServletRequest) req, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest((HttpServletRequest) req, scope.span());
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Argument(0) final ServletRequest request,
|
@Advice.Argument(0) final ServletRequest request,
|
||||||
@Advice.Argument(1) final ServletResponse response,
|
@Advice.Argument(1) final ServletResponse response,
|
||||||
@Advice.Enter final ActiveSpan span,
|
@Advice.Enter final Scope scope,
|
||||||
@Advice.Thrown final Throwable throwable) {
|
@Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
||||||
|
final Span span = scope.span();
|
||||||
final HttpServletRequest req = (HttpServletRequest) request;
|
final HttpServletRequest req = (HttpServletRequest) request;
|
||||||
final HttpServletResponse resp = (HttpServletResponse) response;
|
final HttpServletResponse resp = (HttpServletResponse) response;
|
||||||
|
|
||||||
|
@ -104,7 +107,7 @@ public final class FilterChain2Instrumentation implements Instrumenter {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.HelperInjector;
|
import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
||||||
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
||||||
|
@ -20,6 +21,8 @@ import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||||
|
@ -60,42 +63,51 @@ public final class HttpServlet2Instrumentation implements Instrumenter {
|
||||||
public static class HttpServlet2Advice {
|
public static class HttpServlet2Advice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.Argument(0) final HttpServletRequest req) {
|
public static Scope startSpan(@Advice.Argument(0) final ServletRequest req) {
|
||||||
if (GlobalTracer.get().activeSpan() != null) {
|
if (GlobalTracer.get().scopeManager().active() != null
|
||||||
// Tracing might already be applied by the FilterChain. If so ignore this.
|
|| !(req instanceof HttpServletRequest)) {
|
||||||
|
// doFilter is called by each filter. We only want to time outer-most.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SpanContext extractedContext =
|
final SpanContext extractedContext =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.extract(Format.Builtin.HTTP_HEADERS, new HttpServletRequestExtractAdapter(req));
|
.extract(
|
||||||
|
Format.Builtin.HTTP_HEADERS,
|
||||||
|
new HttpServletRequestExtractAdapter((HttpServletRequest) req));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan(SERVLET_OPERATION_NAME)
|
.buildSpan(SERVLET_OPERATION_NAME)
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest(req, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest((HttpServletRequest) req, scope.span());
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Argument(0) final HttpServletRequest req,
|
@Advice.Argument(0) final ServletRequest request,
|
||||||
@Advice.Argument(1) final HttpServletResponse resp,
|
@Advice.Argument(1) final ServletResponse response,
|
||||||
@Advice.Enter final ActiveSpan span,
|
@Advice.Enter final Scope scope,
|
||||||
@Advice.Thrown final Throwable throwable) {
|
@Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (throwable != null) {
|
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
final Span span = scope.span();
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
final HttpServletRequest req = (HttpServletRequest) request;
|
||||||
} else {
|
final HttpServletResponse resp = (HttpServletResponse) response;
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
|
||||||
|
if (throwable != null) {
|
||||||
|
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
||||||
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
|
} else {
|
||||||
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
span.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
|
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
|
||||||
compile('io.opentracing.contrib:opentracing-web-servlet-filter:0.0.9') {
|
compile('io.opentracing.contrib:opentracing-web-servlet-filter:0.1.0-RC1') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.HelperInjector;
|
import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
||||||
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
||||||
|
@ -56,16 +57,16 @@ public final class FilterChain3Instrumentation implements Instrumenter {
|
||||||
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
|
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
|
||||||
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
|
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
|
||||||
.and(isPublic()),
|
.and(isPublic()),
|
||||||
HttpServlet3Advice.class.getName()))
|
FilterChain3Advice.class.getName()))
|
||||||
.asDecorator();
|
.asDecorator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HttpServlet3Advice {
|
public static class FilterChain3Advice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.Argument(0) final ServletRequest req) {
|
public static Scope startSpan(@Advice.Argument(0) final ServletRequest req) {
|
||||||
if (GlobalTracer.get().activeSpan() != null || !(req instanceof HttpServletRequest)) {
|
if (GlobalTracer.get().activeSpan() != null || !(req instanceof HttpServletRequest)) {
|
||||||
// doFilter is called by each filter. We only want to time outer-most.
|
// Tracing might already be applied by the FilterChain. If so ignore this.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,63 +76,61 @@ public final class FilterChain3Instrumentation implements Instrumenter {
|
||||||
Format.Builtin.HTTP_HEADERS,
|
Format.Builtin.HTTP_HEADERS,
|
||||||
new HttpServletRequestExtractAdapter((HttpServletRequest) req));
|
new HttpServletRequestExtractAdapter((HttpServletRequest) req));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan(SERVLET_OPERATION_NAME)
|
.buildSpan(SERVLET_OPERATION_NAME)
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
||||||
.startActive();
|
.startActive(false);
|
||||||
|
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest((HttpServletRequest) req, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest((HttpServletRequest) req, scope.span());
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Argument(0) final ServletRequest request,
|
@Advice.Argument(0) final ServletRequest request,
|
||||||
@Advice.Argument(1) final ServletResponse response,
|
@Advice.Argument(1) final ServletResponse response,
|
||||||
@Advice.Enter final ActiveSpan span,
|
@Advice.Enter final Scope scope,
|
||||||
@Advice.Thrown final Throwable throwable) {
|
@Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
||||||
final HttpServletRequest req = (HttpServletRequest) request;
|
final HttpServletRequest req = (HttpServletRequest) request;
|
||||||
final HttpServletResponse resp = (HttpServletResponse) response;
|
final HttpServletResponse resp = (HttpServletResponse) response;
|
||||||
|
final Span span = scope.span();
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
|
scope.close();
|
||||||
|
scope.span().finish(); // Finish the span manually since finishSpanOnClose was false
|
||||||
} else if (req.isAsyncStarted()) {
|
} else if (req.isAsyncStarted()) {
|
||||||
final ActiveSpan.Continuation cont = span.capture();
|
|
||||||
final AtomicBoolean activated = new AtomicBoolean(false);
|
final AtomicBoolean activated = new AtomicBoolean(false);
|
||||||
// what if async is already finished? This would not be called
|
// what if async is already finished? This would not be called
|
||||||
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, cont, span));
|
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, span));
|
||||||
} else {
|
} else {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
||||||
|
scope.close();
|
||||||
|
scope.span().finish(); // Finish the span manually since finishSpanOnClose was false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span.deactivate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TagSettingAsyncListener implements AsyncListener {
|
public static class TagSettingAsyncListener implements AsyncListener {
|
||||||
private final AtomicBoolean activated;
|
private final AtomicBoolean activated;
|
||||||
private final ActiveSpan.Continuation cont;
|
private final Span span;
|
||||||
private final ActiveSpan span;
|
|
||||||
|
|
||||||
public TagSettingAsyncListener(
|
public TagSettingAsyncListener(final AtomicBoolean activated, final Span span) {
|
||||||
final AtomicBoolean activated,
|
|
||||||
final ActiveSpan.Continuation cont,
|
|
||||||
final ActiveSpan span) {
|
|
||||||
this.activated = activated;
|
this.activated = activated;
|
||||||
this.cont = cont;
|
|
||||||
this.span = span;
|
this.span = span;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(final AsyncEvent event) throws IOException {
|
public void onComplete(final AsyncEvent event) throws IOException {
|
||||||
if (activated.compareAndSet(false, true)) {
|
if (activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
@ -143,7 +142,7 @@ public final class FilterChain3Instrumentation implements Instrumenter {
|
||||||
@Override
|
@Override
|
||||||
public void onTimeout(final AsyncEvent event) throws IOException {
|
public void onTimeout(final AsyncEvent event) throws IOException {
|
||||||
if (activated.compareAndSet(false, true)) {
|
if (activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onTimeout(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onTimeout(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
@ -156,7 +155,7 @@ public final class FilterChain3Instrumentation implements Instrumenter {
|
||||||
@Override
|
@Override
|
||||||
public void onError(final AsyncEvent event) throws IOException {
|
public void onError(final AsyncEvent event) throws IOException {
|
||||||
if (event.getThrowable() != null && activated.compareAndSet(false, true)) {
|
if (event.getThrowable() != null && activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onError(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onError(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
|
|
@ -12,7 +12,8 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.HelperInjector;
|
import datadog.trace.agent.tooling.HelperInjector;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
import io.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter;
|
||||||
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
|
||||||
|
@ -61,8 +62,8 @@ public final class HttpServlet3Instrumentation implements Instrumenter {
|
||||||
public static class HttpServlet3Advice {
|
public static class HttpServlet3Advice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.Argument(0) final HttpServletRequest req) {
|
public static Scope startSpan(@Advice.Argument(0) final HttpServletRequest req) {
|
||||||
if (GlobalTracer.get().activeSpan() != null) {
|
if (GlobalTracer.get().scopeManager().active() != null) {
|
||||||
// Tracing might already be applied by the FilterChain. If so ignore this.
|
// Tracing might already be applied by the FilterChain. If so ignore this.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -71,58 +72,56 @@ public final class HttpServlet3Instrumentation implements Instrumenter {
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.extract(Format.Builtin.HTTP_HEADERS, new HttpServletRequestExtractAdapter(req));
|
.extract(Format.Builtin.HTTP_HEADERS, new HttpServletRequestExtractAdapter(req));
|
||||||
|
|
||||||
final ActiveSpan span =
|
final Scope scope =
|
||||||
GlobalTracer.get()
|
GlobalTracer.get()
|
||||||
.buildSpan(SERVLET_OPERATION_NAME)
|
.buildSpan(SERVLET_OPERATION_NAME)
|
||||||
.asChildOf(extractedContext)
|
.asChildOf(extractedContext)
|
||||||
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
|
||||||
.startActive();
|
.startActive(false);
|
||||||
|
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest(req, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onRequest(req, scope.span());
|
||||||
return span;
|
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 stopSpan(
|
||||||
@Advice.Argument(0) final HttpServletRequest req,
|
@Advice.Argument(0) final HttpServletRequest req,
|
||||||
@Advice.Argument(1) final HttpServletResponse resp,
|
@Advice.Argument(1) final HttpServletResponse resp,
|
||||||
@Advice.Enter final ActiveSpan span,
|
@Advice.Enter final Scope scope,
|
||||||
@Advice.Thrown final Throwable throwable) {
|
@Advice.Thrown final Throwable throwable) {
|
||||||
|
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
|
final Span span = scope.span();
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onError(req, resp, throwable, span);
|
||||||
span.log(Collections.singletonMap("error.object", throwable));
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
|
scope.close();
|
||||||
|
scope.span().finish(); // Finish the span manually since finishSpanOnClose was false
|
||||||
} else if (req.isAsyncStarted()) {
|
} else if (req.isAsyncStarted()) {
|
||||||
final ActiveSpan.Continuation cont = span.capture();
|
|
||||||
final AtomicBoolean activated = new AtomicBoolean(false);
|
final AtomicBoolean activated = new AtomicBoolean(false);
|
||||||
// what if async is already finished? This would not be called
|
// what if async is already finished? This would not be called
|
||||||
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, cont, span));
|
req.getAsyncContext().addListener(new TagSettingAsyncListener(activated, span));
|
||||||
} else {
|
} else {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(req, resp, span);
|
||||||
|
scope.close();
|
||||||
|
scope.span().finish(); // Finish the span manually since finishSpanOnClose was false
|
||||||
}
|
}
|
||||||
span.deactivate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TagSettingAsyncListener implements AsyncListener {
|
public static class TagSettingAsyncListener implements AsyncListener {
|
||||||
private final AtomicBoolean activated;
|
private final AtomicBoolean activated;
|
||||||
private final ActiveSpan.Continuation cont;
|
private final Span span;
|
||||||
private final ActiveSpan span;
|
|
||||||
|
|
||||||
public TagSettingAsyncListener(
|
public TagSettingAsyncListener(final AtomicBoolean activated, final Span span) {
|
||||||
final AtomicBoolean activated,
|
|
||||||
final ActiveSpan.Continuation cont,
|
|
||||||
final ActiveSpan span) {
|
|
||||||
this.activated = activated;
|
this.activated = activated;
|
||||||
this.cont = cont;
|
|
||||||
this.span = span;
|
this.span = span;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(final AsyncEvent event) throws IOException {
|
public void onComplete(final AsyncEvent event) throws IOException {
|
||||||
if (activated.compareAndSet(false, true)) {
|
if (activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onResponse(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
@ -134,7 +133,7 @@ public final class HttpServlet3Instrumentation implements Instrumenter {
|
||||||
@Override
|
@Override
|
||||||
public void onTimeout(final AsyncEvent event) throws IOException {
|
public void onTimeout(final AsyncEvent event) throws IOException {
|
||||||
if (activated.compareAndSet(false, true)) {
|
if (activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onTimeout(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onTimeout(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
@ -147,7 +146,7 @@ public final class HttpServlet3Instrumentation implements Instrumenter {
|
||||||
@Override
|
@Override
|
||||||
public void onError(final AsyncEvent event) throws IOException {
|
public void onError(final AsyncEvent event) throws IOException {
|
||||||
if (event.getThrowable() != null && activated.compareAndSet(false, true)) {
|
if (event.getThrowable() != null && activated.compareAndSet(false, true)) {
|
||||||
try (ActiveSpan activeSpan = cont.activate()) {
|
try (Scope scope = GlobalTracer.get().scopeManager().activate(span, true)) {
|
||||||
ServletFilterSpanDecorator.STANDARD_TAGS.onError(
|
ServletFilterSpanDecorator.STANDARD_TAGS.onError(
|
||||||
(HttpServletRequest) event.getSuppliedRequest(),
|
(HttpServletRequest) event.getSuppliedRequest(),
|
||||||
(HttpServletResponse) event.getSuppliedResponse(),
|
(HttpServletResponse) event.getSuppliedResponse(),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -52,13 +52,13 @@ public final class SpringWebInstrumentation implements Instrumenter {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void nameResource(@Advice.Argument(0) final HttpServletRequest request) {
|
public static void nameResource(@Advice.Argument(0) final HttpServletRequest request) {
|
||||||
final ActiveSpan span = GlobalTracer.get().activeSpan();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (span != null) {
|
if (scope != null) {
|
||||||
final String method = request.getMethod();
|
final String method = request.getMethod();
|
||||||
final String bestMatchingPattern =
|
final String bestMatchingPattern =
|
||||||
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
|
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
|
||||||
final String resourceName = method + " " + bestMatchingPattern;
|
final String resourceName = method + " " + bestMatchingPattern;
|
||||||
span.setTag(DDTags.RESOURCE_NAME, resourceName);
|
scope.span().setTag(DDTags.RESOURCE_NAME, resourceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ import com.google.auto.service.AutoService;
|
||||||
import datadog.trace.agent.tooling.DDAdvice;
|
import datadog.trace.agent.tooling.DDAdvice;
|
||||||
import datadog.trace.agent.tooling.Instrumenter;
|
import datadog.trace.agent.tooling.Instrumenter;
|
||||||
import datadog.trace.api.Trace;
|
import datadog.trace.api.Trace;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
import io.opentracing.tag.Tags;
|
import io.opentracing.tag.Tags;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -35,24 +36,25 @@ public final class TraceAnnotationInstrumentation implements Instrumenter {
|
||||||
public static class TraceAdvice {
|
public static class TraceAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static ActiveSpan startSpan(@Advice.Origin final Method method) {
|
public static Scope startSpan(@Advice.Origin final Method method) {
|
||||||
final Trace trace = method.getAnnotation(Trace.class);
|
final Trace trace = method.getAnnotation(Trace.class);
|
||||||
String operationName = trace == null ? null : trace.operationName();
|
String operationName = trace == null ? null : trace.operationName();
|
||||||
if (operationName == null || operationName.isEmpty()) {
|
if (operationName == null || operationName.isEmpty()) {
|
||||||
operationName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
operationName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return GlobalTracer.get().buildSpan(operationName).startActive();
|
return GlobalTracer.get().buildSpan(operationName).startActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Enter final ActiveSpan activeSpan, @Advice.Thrown final Throwable throwable) {
|
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
Tags.ERROR.set(activeSpan, true);
|
final Span span = scope.span();
|
||||||
activeSpan.log(Collections.singletonMap("error.object", throwable));
|
Tags.ERROR.set(span, true);
|
||||||
|
span.log(Collections.singletonMap("error.object", throwable));
|
||||||
}
|
}
|
||||||
activeSpan.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package datadog.trace.agent.test;
|
package datadog.trace.agent.test;
|
||||||
|
|
||||||
import datadog.trace.agent.tooling.Utils;
|
import datadog.trace.agent.tooling.Utils;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -55,15 +55,13 @@ public class TestUtils {
|
||||||
|
|
||||||
public static <T extends Object> Object runUnderTrace(
|
public static <T extends Object> Object runUnderTrace(
|
||||||
final String rootOperationName, final Callable<T> r) {
|
final String rootOperationName, final Callable<T> r) {
|
||||||
final ActiveSpan rootSpan = GlobalTracer.get().buildSpan(rootOperationName).startActive();
|
final Scope scope = GlobalTracer.get().buildSpan(rootOperationName).startActive(true);
|
||||||
try {
|
try {
|
||||||
try {
|
return r.call();
|
||||||
return r.call();
|
} catch (final Exception e) {
|
||||||
} catch (final Exception e) {
|
throw new IllegalStateException(e);
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
rootSpan.deactivate();
|
scope.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ accessible through the method `buildSpan(String operationName)` to serve this pu
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Create a new Span with the operation name "componentTracking"
|
// Create a new Span with the operation name "componentTracking"
|
||||||
ActiveSpan current = tracer.buildSpan("componentTracking").startActive();
|
ActiveSpan current = tracer.buildSpan("componentTracking").startActive(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
This example creates a simple span referenced "componentTracking". The `startActive()` method starts a new span and sets it
|
This example creates a simple span referenced "componentTracking". The `startActive()` method starts a new span and sets it
|
||||||
|
@ -94,7 +94,7 @@ OpenTracing defines a [standard set of tags](https://github.com/opentracing/spec
|
||||||
buildSpan("componentTracking")
|
buildSpan("componentTracking")
|
||||||
.withTag("custom-meta", "some-useful-value")
|
.withTag("custom-meta", "some-useful-value")
|
||||||
.withTag(Tags.COMPONENT, "my-component-mysql")
|
.withTag(Tags.COMPONENT, "my-component-mysql")
|
||||||
.startActive();
|
.startActive(true);
|
||||||
|
|
||||||
|
|
||||||
// Somewhere further in the code
|
// Somewhere further in the code
|
||||||
|
@ -154,7 +154,7 @@ Spans are associated across processes in a trace via the `Tracer.extract` and `T
|
||||||
```java
|
```java
|
||||||
// On the start of a new trace in an application, associate incoming request with existing traces.
|
// On the start of a new trace in an application, associate incoming request with existing traces.
|
||||||
SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, someTextMapInstance);
|
SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, someTextMapInstance);
|
||||||
ActiveSpan currentSpan = tracer.buildSpan("componentTracking").asChildOf(spanCtx).startActive();
|
ActiveSpan currentSpan = tracer.buildSpan("componentTracking").asChildOf(spanCtx).startActive(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
|
@ -2,21 +2,20 @@ package datadog.trace;
|
||||||
|
|
||||||
import datadog.opentracing.DDTracer;
|
import datadog.opentracing.DDTracer;
|
||||||
import datadog.trace.common.writer.ListWriter;
|
import datadog.trace.common.writer.ListWriter;
|
||||||
import io.opentracing.ActiveSpan;
|
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.Scope;
|
|
||||||
import org.openjdk.jmh.annotations.State;
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
|
||||||
public class DDTraceBenchmark {
|
public class DDTraceBenchmark {
|
||||||
public static String SPAN_NAME = "span-benchmark";
|
public static String SPAN_NAME = "span-benchmark";
|
||||||
|
|
||||||
@State(Scope.Thread)
|
@State(org.openjdk.jmh.annotations.Scope.Thread)
|
||||||
public static class TraceState {
|
public static class TraceState {
|
||||||
public ListWriter traceCollector = new ListWriter();
|
public ListWriter traceCollector = new ListWriter();
|
||||||
public Tracer tracer = new DDTracer(traceCollector);
|
public Tracer tracer = new DDTracer(traceCollector);
|
||||||
public ActiveSpan activeSpan = tracer.buildSpan(SPAN_NAME).startActive();
|
// TODO: this will need to be fixed if we want backwards compatibility for older versions...
|
||||||
|
public io.opentracing.Scope scope = tracer.buildSpan(SPAN_NAME).startActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
|
@ -38,23 +37,13 @@ public class DDTraceBenchmark {
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Object testBuildStartSpanActive(final TraceState state) {
|
public Object testBuildStartSpanActive(final TraceState state) {
|
||||||
return state.tracer.buildSpan(SPAN_NAME).startActive();
|
return state.tracer.buildSpan(SPAN_NAME).startActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Object testFullActiveSpan(final TraceState state) {
|
public Object testFullActiveSpan(final TraceState state) {
|
||||||
final ActiveSpan activeSpan = state.tracer.buildSpan(SPAN_NAME).startActive();
|
final io.opentracing.Scope scope = state.tracer.buildSpan(SPAN_NAME).startActive(true);
|
||||||
activeSpan.deactivate();
|
scope.close();
|
||||||
return activeSpan;
|
return scope;
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public Object testContinuationCapture(final TraceState state) {
|
|
||||||
return state.activeSpan.capture();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public Object testContinuationActivate(final TraceState state) {
|
|
||||||
return state.activeSpan.capture().activate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,339 +0,0 @@
|
||||||
package datadog.opentracing;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import datadog.trace.api.DDTags;
|
|
||||||
import datadog.trace.common.util.Clock;
|
|
||||||
import io.opentracing.BaseSpan;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public abstract class DDBaseSpan<S extends BaseSpan> implements BaseSpan<S> {
|
|
||||||
|
|
||||||
/** The context attached to the span */
|
|
||||||
protected final DDSpanContext context;
|
|
||||||
/** StartTime stores the creation time of the span in milliseconds */
|
|
||||||
protected long startTimeMicro;
|
|
||||||
/** StartTimeNano stores the only the nanoseconds for more accuracy */
|
|
||||||
protected long startTimeNano;
|
|
||||||
/** The duration in nanoseconds computed using the startTimeMicro and startTimeNano */
|
|
||||||
protected long durationNano;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple constructor. Currently, users have
|
|
||||||
*
|
|
||||||
* @param timestampMicro if set, use this time instead of the auto-generated time
|
|
||||||
* @param context the context
|
|
||||||
*/
|
|
||||||
protected DDBaseSpan(final long timestampMicro, final DDSpanContext context) {
|
|
||||||
|
|
||||||
this.context = context;
|
|
||||||
|
|
||||||
// record the start time in nano (current milli + nano delta)
|
|
||||||
if (timestampMicro == 0L) {
|
|
||||||
this.startTimeMicro = Clock.currentMicroTime();
|
|
||||||
} else {
|
|
||||||
this.startTimeMicro = timestampMicro;
|
|
||||||
}
|
|
||||||
this.startTimeNano = Clock.currentNanoTicks();
|
|
||||||
|
|
||||||
// track each span of the trace
|
|
||||||
this.context.getTrace().add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void finish() {
|
|
||||||
finish(Clock.currentMicroTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void finish(final long stoptimeMicros) {
|
|
||||||
// Ensure that duration is at least 1. Less than 1 is possible due to our use of system clock instead of nano time.
|
|
||||||
this.durationNano =
|
|
||||||
Math.max(1, TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - this.startTimeMicro));
|
|
||||||
afterFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the span. If the current span is the parent, check if each child has also been closed If
|
|
||||||
* not, warned it
|
|
||||||
*/
|
|
||||||
protected final void afterFinish() {
|
|
||||||
log.debug("{} - Closing the span.", this);
|
|
||||||
|
|
||||||
// warn if one of the parent's children is not finished
|
|
||||||
if (this.isRootSpan()) {
|
|
||||||
final Queue<DDBaseSpan<?>> spans = this.context().getTrace();
|
|
||||||
|
|
||||||
for (final DDBaseSpan<?> span : spans) {
|
|
||||||
if (span.getDurationNano() == 0L) {
|
|
||||||
log.warn(
|
|
||||||
"{} - The parent span is marked as finished but this span isn't. You have to close each children.",
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.context.getTracer().write(this.context.getTrace());
|
|
||||||
log.debug("{} - Write the trace", this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the span is the root parent. It means that the traceId is the same as the spanId
|
|
||||||
*
|
|
||||||
* @return true if root, false otherwise
|
|
||||||
*/
|
|
||||||
protected final boolean isRootSpan() {
|
|
||||||
|
|
||||||
if (context().getTrace().isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// First item of the array AND tracer set
|
|
||||||
final DDBaseSpan<?> first = context().getTrace().peek();
|
|
||||||
return first.context().getSpanId() == this.context().getSpanId()
|
|
||||||
&& this.context.getTracer() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setErrorMeta(final Throwable error) {
|
|
||||||
context.setErrorFlag(true);
|
|
||||||
|
|
||||||
setTag(DDTags.ERROR_MSG, error.getMessage());
|
|
||||||
setTag(DDTags.ERROR_TYPE, error.getClass().getName());
|
|
||||||
|
|
||||||
final StringWriter errorString = new StringWriter();
|
|
||||||
error.printStackTrace(new PrintWriter(errorString));
|
|
||||||
setTag(DDTags.ERROR_STACK, errorString.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean extractError(final Map<String, ?> map) {
|
|
||||||
if (map.get("error.object") instanceof Throwable) {
|
|
||||||
final Throwable error = (Throwable) map.get("error.object");
|
|
||||||
setErrorMeta(error);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S setTag(final String tag, final String value) {
|
|
||||||
this.context().setTag(tag, (Object) value);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#setTag(java.lang.String, boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S setTag(final String tag, final boolean value) {
|
|
||||||
this.context().setTag(tag, (Object) value);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.Number)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S setTag(final String tag, final Number value) {
|
|
||||||
this.context().setTag(tag, (Object) value);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#context()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final DDSpanContext context() {
|
|
||||||
return this.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#getBaggageItem(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String getBaggageItem(final String key) {
|
|
||||||
return this.context.getBaggageItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#setBaggageItem(java.lang.String, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S setBaggageItem(final String key, final String value) {
|
|
||||||
this.context.setBaggageItem(key, value);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#setOperationName(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S setOperationName(final String operationName) {
|
|
||||||
this.context().setOperationName(operationName);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(java.util.Map)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final Map<String, ?> map) {
|
|
||||||
if (!extractError(map)) {
|
|
||||||
log.debug("`log` method is not implemented. Doing nothing");
|
|
||||||
}
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(long, java.util.Map)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final long l, final Map<String, ?> map) {
|
|
||||||
if (!extractError(map)) {
|
|
||||||
log.debug("`log` method is not implemented. Doing nothing");
|
|
||||||
}
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final String s) {
|
|
||||||
log.debug("`log` method is not implemented. Provided log: {}", s);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(long, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final long l, final String s) {
|
|
||||||
log.debug("`log` method is not implemented. Provided log: {}", s);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(java.lang.String, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final String s, final Object o) {
|
|
||||||
log.debug("`log` method is not implemented. Provided log: {}", s);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see io.opentracing.BaseSpan#log(long, java.lang.String, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final S log(final long l, final String s, final Object o) {
|
|
||||||
log.debug("`log` method is not implemented. Provided log: {}", s);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final S setServiceName(final String serviceName) {
|
|
||||||
this.context().setServiceName(serviceName);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final S setResourceName(final String resourceName) {
|
|
||||||
this.context().setResourceName(resourceName);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final S setSpanType(final String type) {
|
|
||||||
this.context().setSpanType(type);
|
|
||||||
return thisInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract S thisInstance();
|
|
||||||
|
|
||||||
// Getters and JSON serialisation instructions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Meta merges baggage and tags (stringified values)
|
|
||||||
*
|
|
||||||
* @return merged context baggage and tags
|
|
||||||
*/
|
|
||||||
@JsonGetter
|
|
||||||
public Map<String, String> getMeta() {
|
|
||||||
final Map<String, String> meta = new HashMap<>();
|
|
||||||
for (final Entry<String, String> entry : context().getBaggageItems().entrySet()) {
|
|
||||||
meta.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
for (final Entry<String, Object> entry : getTags().entrySet()) {
|
|
||||||
meta.put(entry.getKey(), String.valueOf(entry.getValue()));
|
|
||||||
}
|
|
||||||
return meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("start")
|
|
||||||
public long getStartTime() {
|
|
||||||
return startTimeMicro * 1000L;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("duration")
|
|
||||||
public long getDurationNano() {
|
|
||||||
return durationNano;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("service")
|
|
||||||
public String getServiceName() {
|
|
||||||
return context.getServiceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("trace_id")
|
|
||||||
public long getTraceId() {
|
|
||||||
return context.getTraceId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("span_id")
|
|
||||||
public long getSpanId() {
|
|
||||||
return context.getSpanId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("parent_id")
|
|
||||||
public long getParentId() {
|
|
||||||
return context.getParentId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("resource")
|
|
||||||
public String getResourceName() {
|
|
||||||
return context.getResourceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter("name")
|
|
||||||
public String getOperationName() {
|
|
||||||
return context.getOperationName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public Map<String, Object> getTags() {
|
|
||||||
return this.context().getTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter
|
|
||||||
public String getType() {
|
|
||||||
return context.getSpanType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonGetter
|
|
||||||
public int getError() {
|
|
||||||
return context.getErrorFlag() ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new StringBuilder()
|
|
||||||
.append(context.toString())
|
|
||||||
.append(", duration_ns=")
|
|
||||||
.append(durationNano)
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,17 @@
|
||||||
package datadog.opentracing;
|
package datadog.opentracing;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import datadog.trace.api.DDTags;
|
||||||
|
import datadog.trace.common.util.Clock;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an in-flight span in the opentracing system.
|
* Represents an in-flight span in the opentracing system.
|
||||||
|
@ -8,7 +19,17 @@ import io.opentracing.Span;
|
||||||
* <p>Spans are created by the {@link DDTracer#buildSpan}. This implementation adds some features
|
* <p>Spans are created by the {@link DDTracer#buildSpan}. This implementation adds some features
|
||||||
* according to the DD agent.
|
* according to the DD agent.
|
||||||
*/
|
*/
|
||||||
public class DDSpan extends DDBaseSpan<Span> implements Span {
|
@Slf4j
|
||||||
|
public class DDSpan implements Span {
|
||||||
|
|
||||||
|
/** The context attached to the span */
|
||||||
|
protected final DDSpanContext context;
|
||||||
|
/** StartTime stores the creation time of the span in milliseconds */
|
||||||
|
protected long startTimeMicro;
|
||||||
|
/** StartTimeNano stores the only the nanoseconds for more accuracy */
|
||||||
|
protected long startTimeNano;
|
||||||
|
/** The duration in nanoseconds computed using the startTimeMicro and startTimeNano */
|
||||||
|
protected long durationNano;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple constructor. Currently, users have
|
* A simple constructor. Currently, users have
|
||||||
|
@ -17,11 +38,289 @@ public class DDSpan extends DDBaseSpan<Span> implements Span {
|
||||||
* @param context the context
|
* @param context the context
|
||||||
*/
|
*/
|
||||||
protected DDSpan(final long timestampMicro, final DDSpanContext context) {
|
protected DDSpan(final long timestampMicro, final DDSpanContext context) {
|
||||||
super(timestampMicro, context);
|
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
// record the start time in nano (current milli + nano delta)
|
||||||
|
if (timestampMicro == 0L) {
|
||||||
|
this.startTimeMicro = Clock.currentMicroTime();
|
||||||
|
} else {
|
||||||
|
this.startTimeMicro = timestampMicro;
|
||||||
|
}
|
||||||
|
this.startTimeNano = Clock.currentNanoTicks();
|
||||||
|
|
||||||
|
// track each span of the trace
|
||||||
|
this.context.getTrace().add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DDSpan thisInstance() {
|
public final void finish() {
|
||||||
|
finish(Clock.currentMicroTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void finish(final long stoptimeMicros) {
|
||||||
|
// Ensure that duration is at least 1. Less than 1 is possible due to our use of system clock instead of nano time.
|
||||||
|
this.durationNano =
|
||||||
|
Math.max(1, TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - this.startTimeMicro));
|
||||||
|
afterFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the span. If the current span is the parent, check if each child has also been closed If
|
||||||
|
* not, warned it
|
||||||
|
*/
|
||||||
|
protected final void afterFinish() {
|
||||||
|
log.debug("{} - Closing the span.", this);
|
||||||
|
|
||||||
|
// warn if one of the parent's children is not finished
|
||||||
|
if (this.isRootSpan()) {
|
||||||
|
final Queue<DDSpan> spans = this.context().getTrace();
|
||||||
|
|
||||||
|
for (final DDSpan span : spans) {
|
||||||
|
if (span.getDurationNano() == 0L) {
|
||||||
|
log.warn(
|
||||||
|
"{} - The parent span is marked as finished but this span isn't. You have to close each children.",
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.context.getTracer().write(this.context.getTrace());
|
||||||
|
log.debug("{} - Write the trace", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the span is the root parent. It means that the traceId is the same as the spanId
|
||||||
|
*
|
||||||
|
* @return true if root, false otherwise
|
||||||
|
*/
|
||||||
|
protected final boolean isRootSpan() {
|
||||||
|
|
||||||
|
if (context().getTrace().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// First item of the array AND tracer set
|
||||||
|
final DDSpan first = context().getTrace().peek();
|
||||||
|
return first.context().getSpanId() == this.context().getSpanId()
|
||||||
|
&& this.context.getTracer() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMeta(final Throwable error) {
|
||||||
|
context.setErrorFlag(true);
|
||||||
|
|
||||||
|
setTag(DDTags.ERROR_MSG, error.getMessage());
|
||||||
|
setTag(DDTags.ERROR_TYPE, error.getClass().getName());
|
||||||
|
|
||||||
|
final StringWriter errorString = new StringWriter();
|
||||||
|
error.printStackTrace(new PrintWriter(errorString));
|
||||||
|
setTag(DDTags.ERROR_STACK, errorString.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean extractError(final Map<String, ?> map) {
|
||||||
|
if (map.get("error.object") instanceof Throwable) {
|
||||||
|
final Throwable error = (Throwable) map.get("error.object");
|
||||||
|
setErrorMeta(error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final Span setTag(final String tag, final String value) {
|
||||||
|
this.context().setTag(tag, (Object) value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#setTag(java.lang.String, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final Span setTag(final String tag, final boolean value) {
|
||||||
|
this.context().setTag(tag, (Object) value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.Number)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final Span setTag(final String tag, final Number value) {
|
||||||
|
this.context().setTag(tag, (Object) value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#context()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpanContext context() {
|
||||||
|
return this.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#getBaggageItem(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final String getBaggageItem(final String key) {
|
||||||
|
return this.context.getBaggageItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#setBaggageItem(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan setBaggageItem(final String key, final String value) {
|
||||||
|
this.context.setBaggageItem(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#setOperationName(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan setOperationName(final String operationName) {
|
||||||
|
this.context().setOperationName(operationName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#log(java.util.Map)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan log(final Map<String, ?> map) {
|
||||||
|
if (!extractError(map)) {
|
||||||
|
log.debug("`log` method is not implemented. Doing nothing");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#log(long, java.util.Map)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan log(final long l, final Map<String, ?> map) {
|
||||||
|
if (!extractError(map)) {
|
||||||
|
log.debug("`log` method is not implemented. Doing nothing");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#log(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan log(final String s) {
|
||||||
|
log.debug("`log` method is not implemented. Provided log: {}", s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see io.opentracing.BaseSpan#log(long, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final DDSpan log(final long l, final String s) {
|
||||||
|
log.debug("`log` method is not implemented. Provided log: {}", s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DDSpan setServiceName(final String serviceName) {
|
||||||
|
this.context().setServiceName(serviceName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DDSpan setResourceName(final String resourceName) {
|
||||||
|
this.context().setResourceName(resourceName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DDSpan setSpanType(final String type) {
|
||||||
|
this.context().setSpanType(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and JSON serialisation instructions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meta merges baggage and tags (stringified values)
|
||||||
|
*
|
||||||
|
* @return merged context baggage and tags
|
||||||
|
*/
|
||||||
|
@JsonGetter
|
||||||
|
public Map<String, String> getMeta() {
|
||||||
|
final Map<String, String> meta = new HashMap<>();
|
||||||
|
for (final Map.Entry<String, String> entry : context().getBaggageItems().entrySet()) {
|
||||||
|
meta.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
for (final Map.Entry<String, Object> entry : getTags().entrySet()) {
|
||||||
|
meta.put(entry.getKey(), String.valueOf(entry.getValue()));
|
||||||
|
}
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("start")
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTimeMicro * 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("duration")
|
||||||
|
public long getDurationNano() {
|
||||||
|
return durationNano;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("service")
|
||||||
|
public String getServiceName() {
|
||||||
|
return context.getServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("trace_id")
|
||||||
|
public long getTraceId() {
|
||||||
|
return context.getTraceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("span_id")
|
||||||
|
public long getSpanId() {
|
||||||
|
return context.getSpanId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("parent_id")
|
||||||
|
public long getParentId() {
|
||||||
|
return context.getParentId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("resource")
|
||||||
|
public String getResourceName() {
|
||||||
|
return context.getResourceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter("name")
|
||||||
|
public String getOperationName() {
|
||||||
|
return context.getOperationName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Map<String, Object> getTags() {
|
||||||
|
return this.context().getTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter
|
||||||
|
public String getType() {
|
||||||
|
return context.getSpanType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonGetter
|
||||||
|
public int getError() {
|
||||||
|
return context.getErrorFlag() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new StringBuilder()
|
||||||
|
.append(context.toString())
|
||||||
|
.append(", duration_ns=")
|
||||||
|
.append(durationNano)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class DDSpanContext implements io.opentracing.SpanContext {
|
||||||
private final String threadName = Thread.currentThread().getName();
|
private final String threadName = Thread.currentThread().getName();
|
||||||
private final long threadId = Thread.currentThread().getId();
|
private final long threadId = Thread.currentThread().getId();
|
||||||
/** The collection of all span related to this one */
|
/** The collection of all span related to this one */
|
||||||
private final Queue<DDBaseSpan<?>> trace;
|
private final Queue<DDSpan> trace;
|
||||||
|
|
||||||
// DD attributes
|
// DD attributes
|
||||||
/** For technical reasons, the ref to the original tracer */
|
/** For technical reasons, the ref to the original tracer */
|
||||||
|
@ -64,7 +64,7 @@ public class DDSpanContext implements io.opentracing.SpanContext {
|
||||||
final boolean errorFlag,
|
final boolean errorFlag,
|
||||||
final String spanType,
|
final String spanType,
|
||||||
final Map<String, Object> tags,
|
final Map<String, Object> tags,
|
||||||
final Queue<DDBaseSpan<?>> trace,
|
final Queue<DDSpan> trace,
|
||||||
final DDTracer tracer) {
|
final DDTracer tracer) {
|
||||||
|
|
||||||
this.traceId = traceId;
|
this.traceId = traceId;
|
||||||
|
@ -165,7 +165,7 @@ public class DDSpanContext implements io.opentracing.SpanContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Queue<DDBaseSpan<?>> getTrace() {
|
public Queue<DDSpan> getTrace() {
|
||||||
return this.trace;
|
return this.trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ import datadog.trace.common.Service;
|
||||||
import datadog.trace.common.sampling.AllSampler;
|
import datadog.trace.common.sampling.AllSampler;
|
||||||
import datadog.trace.common.sampling.Sampler;
|
import datadog.trace.common.sampling.Sampler;
|
||||||
import datadog.trace.common.writer.Writer;
|
import datadog.trace.common.writer.Writer;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.ActiveSpanSource;
|
import io.opentracing.ScopeManager;
|
||||||
import io.opentracing.BaseSpan;
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
import io.opentracing.util.ThreadLocalActiveSpanSource;
|
import io.opentracing.util.ThreadLocalScopeManager;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/** DDTracer makes it easy to send traces and span to DD using the OpenTracing API. */
|
/** DDTracer makes it easy to send traces and span to DD using the OpenTracing API. */
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentracing.Tracer {
|
public class DDTracer extends ThreadLocalScopeManager implements io.opentracing.Tracer {
|
||||||
|
|
||||||
public static final String UNASSIGNED_DEFAULT_SERVICE_NAME = "unnamed-java-app";
|
public static final String UNASSIGNED_DEFAULT_SERVICE_NAME = "unnamed-java-app";
|
||||||
|
|
||||||
|
@ -110,6 +110,17 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
spanContextDecorators.put(decorator.getMatchingTag(), list);
|
spanContextDecorators.put(decorator.getMatchingTag(), list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScopeManager scopeManager() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Span activeSpan() {
|
||||||
|
final Scope active = active();
|
||||||
|
return active == null ? null : active.span();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DDSpanBuilder buildSpan(final String operationName) {
|
public DDSpanBuilder buildSpan(final String operationName) {
|
||||||
return new DDSpanBuilder(operationName, this);
|
return new DDSpanBuilder(operationName, this);
|
||||||
|
@ -144,7 +155,7 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
*
|
*
|
||||||
* @param trace a list of the spans related to the same trace
|
* @param trace a list of the spans related to the same trace
|
||||||
*/
|
*/
|
||||||
public void write(final Queue<DDBaseSpan<?>> trace) {
|
public void write(final Queue<DDSpan> trace) {
|
||||||
if (trace.isEmpty()) {
|
if (trace.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +223,7 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
|
|
||||||
/** Spans are built using this builder */
|
/** Spans are built using this builder */
|
||||||
public class DDSpanBuilder implements SpanBuilder {
|
public class DDSpanBuilder implements SpanBuilder {
|
||||||
private final ActiveSpanSource spanSource;
|
private final ScopeManager scopeManager;
|
||||||
|
|
||||||
/** Each span must have an operationName according to the opentracing specification */
|
/** Each span must have an operationName according to the opentracing specification */
|
||||||
private final String operationName;
|
private final String operationName;
|
||||||
|
@ -225,16 +236,16 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
private String resourceName;
|
private String resourceName;
|
||||||
private boolean errorFlag;
|
private boolean errorFlag;
|
||||||
private String spanType;
|
private String spanType;
|
||||||
private boolean ignoreActiveSpan = false;
|
private boolean ignoreScope = false;
|
||||||
|
|
||||||
public DDSpanBuilder(final String operationName, final ActiveSpanSource spanSource) {
|
public DDSpanBuilder(final String operationName, final ScopeManager scopeManager) {
|
||||||
this.operationName = operationName;
|
this.operationName = operationName;
|
||||||
this.spanSource = spanSource;
|
this.scopeManager = scopeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpanBuilder ignoreActiveSpan() {
|
public SpanBuilder ignoreActiveSpan() {
|
||||||
this.ignoreActiveSpan = true;
|
this.ignoreScope = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +254,11 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActiveSpan startActive() {
|
public Scope startActive(final boolean finishSpanOnClose) {
|
||||||
final DDSpan span = startSpan();
|
final DDSpan span = startSpan();
|
||||||
final ActiveSpan activeSpan = spanSource.makeActive(span);
|
final Scope scope = scopeManager.activate(span, finishSpanOnClose);
|
||||||
log.debug("Starting a new active span: {}", span);
|
log.debug("Starting a new active span: {}", span);
|
||||||
return activeSpan;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -320,7 +331,7 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DDSpanBuilder asChildOf(final BaseSpan<?> span) {
|
public DDSpanBuilder asChildOf(final Span span) {
|
||||||
return asChildOf(span == null ? null : span.context());
|
return asChildOf(span == null ? null : span.context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,14 +372,14 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
|
||||||
final long spanId = generateNewId();
|
final long spanId = generateNewId();
|
||||||
final long parentSpanId;
|
final long parentSpanId;
|
||||||
final Map<String, String> baggage;
|
final Map<String, String> baggage;
|
||||||
final Queue<DDBaseSpan<?>> parentTrace;
|
final Queue<DDSpan> parentTrace;
|
||||||
|
|
||||||
final DDSpanContext context;
|
final DDSpanContext context;
|
||||||
SpanContext parentContext = this.parent;
|
SpanContext parentContext = this.parent;
|
||||||
if (parentContext == null && !ignoreActiveSpan) {
|
if (parentContext == null && !ignoreScope) {
|
||||||
// use the ActiveSpan as parent unless overridden or ignored.
|
// use the Scope as parent unless overridden or ignored.
|
||||||
final ActiveSpan activeSpan = activeSpan();
|
final Scope scope = active();
|
||||||
if (activeSpan != null) parentContext = activeSpan.context();
|
if (scope != null) parentContext = scope.span().context();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentContext instanceof DDSpanContext) {
|
if (parentContext instanceof DDSpanContext) {
|
||||||
|
|
|
@ -2,9 +2,9 @@ package datadog.opentracing.resolver;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import datadog.opentracing.DDTracer;
|
import datadog.opentracing.DDTracer;
|
||||||
import io.opentracing.NoopTracerFactory;
|
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import io.opentracing.contrib.tracerresolver.TracerResolver;
|
import io.opentracing.contrib.tracerresolver.TracerResolver;
|
||||||
|
import io.opentracing.noop.NoopTracerFactory;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.common.sampling;
|
package datadog.trace.common.sampling;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -12,7 +12,7 @@ public abstract class AbstractSampler implements Sampler {
|
||||||
protected Map<String, Pattern> skipTagsPatterns = new HashMap<>();
|
protected Map<String, Pattern> skipTagsPatterns = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean sample(final DDBaseSpan<?> span) {
|
public boolean sample(final DDSpan span) {
|
||||||
|
|
||||||
// Filter by tag values
|
// Filter by tag values
|
||||||
for (final Entry<String, Pattern> entry : skipTagsPatterns.entrySet()) {
|
for (final Entry<String, Pattern> entry : skipTagsPatterns.entrySet()) {
|
||||||
|
@ -39,5 +39,5 @@ public abstract class AbstractSampler implements Sampler {
|
||||||
skipTagsPatterns.put(tag, skipPattern);
|
skipTagsPatterns.put(tag, skipPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean doSample(DDBaseSpan<?> span);
|
protected abstract boolean doSample(DDSpan span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package datadog.trace.common.sampling;
|
package datadog.trace.common.sampling;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
|
|
||||||
/** Sampler that always says yes... */
|
/** Sampler that always says yes... */
|
||||||
public class AllSampler extends AbstractSampler {
|
public class AllSampler extends AbstractSampler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean doSample(final DDBaseSpan<?> span) {
|
public boolean doSample(final DDSpan span) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package datadog.trace.common.sampling;
|
package datadog.trace.common.sampling;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sampler sample the traces at a predefined rate.
|
* This sampler sample the traces at a predefined rate.
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* <p>Keep (100 * `sample_rate`)% of the traces. It samples randomly, its main purpose is to reduce
|
* <p>Keep (100 * `sample_rate`)% of the traces. It samples randomly, its main purpose is to reduce
|
||||||
* the integration footprint.
|
* the integration footprint.
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +40,7 @@ public class RateSampler extends AbstractSampler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean doSample(final DDBaseSpan<?> span) {
|
public boolean doSample(final DDSpan span) {
|
||||||
final boolean sample = Math.random() <= this.sampleRate;
|
final boolean sample = Math.random() <= this.sampleRate;
|
||||||
log.debug("{} - Span is sampled: {}", span, sample);
|
log.debug("{} - Span is sampled: {}", span, sample);
|
||||||
return sample;
|
return sample;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.common.sampling;
|
package datadog.trace.common.sampling;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.trace.common.DDTraceConfig;
|
import datadog.trace.common.DDTraceConfig;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -16,7 +16,7 @@ public interface Sampler {
|
||||||
* @param span the parent span with its context
|
* @param span the parent span with its context
|
||||||
* @return true when the trace/spans has to be reported/written
|
* @return true when the trace/spans has to be reported/written
|
||||||
*/
|
*/
|
||||||
boolean sample(DDBaseSpan<?> span);
|
boolean sample(DDSpan span);
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
final class Builder {
|
final class Builder {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package datadog.trace.common.writer;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.trace.common.Service;
|
import datadog.trace.common.Service;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -59,7 +59,7 @@ public class DDAgentWriter implements Writer {
|
||||||
private final DDApi api;
|
private final DDApi api;
|
||||||
|
|
||||||
/** In memory collection of traces waiting for departure */
|
/** In memory collection of traces waiting for departure */
|
||||||
private final WriterQueue<List<DDBaseSpan<?>>> traces;
|
private final WriterQueue<List<DDSpan>> traces;
|
||||||
|
|
||||||
private boolean queueFullReported = false;
|
private boolean queueFullReported = false;
|
||||||
|
|
||||||
|
@ -68,10 +68,10 @@ public class DDAgentWriter implements Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DDAgentWriter(final DDApi api) {
|
public DDAgentWriter(final DDApi api) {
|
||||||
this(api, new WriterQueue<List<DDBaseSpan<?>>>(DEFAULT_MAX_TRACES));
|
this(api, new WriterQueue<List<DDSpan>>(DEFAULT_MAX_TRACES));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DDAgentWriter(final DDApi api, final WriterQueue<List<DDBaseSpan<?>>> queue) {
|
public DDAgentWriter(final DDApi api, final WriterQueue<List<DDSpan>> queue) {
|
||||||
super();
|
super();
|
||||||
this.api = api;
|
this.api = api;
|
||||||
traces = queue;
|
traces = queue;
|
||||||
|
@ -81,8 +81,8 @@ public class DDAgentWriter implements Writer {
|
||||||
* @see datadog.trace.Writer#write(java.util.List)
|
* @see datadog.trace.Writer#write(java.util.List)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(final List<DDBaseSpan<?>> trace) {
|
public void write(final List<DDSpan> trace) {
|
||||||
final List<DDBaseSpan<?>> removed = traces.add(trace);
|
final List<DDSpan> removed = traces.add(trace);
|
||||||
if (removed != null && !queueFullReported) {
|
if (removed != null && !queueFullReported) {
|
||||||
log.debug("Queue is full, traces will be discarded, queue size: {}", DEFAULT_MAX_TRACES);
|
log.debug("Queue is full, traces will be discarded, queue size: {}", DEFAULT_MAX_TRACES);
|
||||||
queueFullReported = true;
|
queueFullReported = true;
|
||||||
|
@ -173,7 +173,7 @@ public class DDAgentWriter implements Writer {
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<List<DDBaseSpan<?>>> payload = traces.getAll();
|
final List<List<DDSpan>> payload = traces.getAll();
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
int nbSpans = 0;
|
int nbSpans = 0;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package datadog.trace.common.writer;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.common.util.concurrent.RateLimiter;
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.opentracing.DDTraceOTInfo;
|
import datadog.opentracing.DDTraceOTInfo;
|
||||||
import datadog.trace.common.Service;
|
import datadog.trace.common.Service;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -42,7 +42,7 @@ public class DDApi {
|
||||||
* @param traces the traces to be sent
|
* @param traces the traces to be sent
|
||||||
* @return the staus code returned
|
* @return the staus code returned
|
||||||
*/
|
*/
|
||||||
public boolean sendTraces(final List<List<DDBaseSpan<?>>> traces) {
|
public boolean sendTraces(final List<List<DDSpan>> traces) {
|
||||||
return putContent("traces", tracesEndpoint, traces, traces.size());
|
return putContent("traces", tracesEndpoint, traces, traces.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.common.writer;
|
package datadog.trace.common.writer;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.trace.common.Service;
|
import datadog.trace.common.Service;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -9,15 +9,15 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
/** List writer used by tests mostly */
|
/** List writer used by tests mostly */
|
||||||
public class ListWriter extends CopyOnWriteArrayList<List<DDBaseSpan<?>>> implements Writer {
|
public class ListWriter extends CopyOnWriteArrayList<List<DDSpan>> implements Writer {
|
||||||
private final List<CountDownLatch> latches = new LinkedList<>();
|
private final List<CountDownLatch> latches = new LinkedList<>();
|
||||||
|
|
||||||
public List<DDBaseSpan<?>> firstTrace() {
|
public List<DDSpan> firstTrace() {
|
||||||
return get(0);
|
return get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(final List<DDBaseSpan<?>> trace) {
|
public void write(final List<DDSpan> trace) {
|
||||||
synchronized (latches) {
|
synchronized (latches) {
|
||||||
add(trace);
|
add(trace);
|
||||||
for (final CountDownLatch latch : latches) {
|
for (final CountDownLatch latch : latches) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package datadog.trace.common.writer;
|
package datadog.trace.common.writer;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.trace.common.Service;
|
import datadog.trace.common.Service;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -12,7 +12,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
public class LoggingWriter implements Writer {
|
public class LoggingWriter implements Writer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(final List<DDBaseSpan<?>> trace) {
|
public void write(final List<DDSpan> trace) {
|
||||||
log.info("write(trace): {}", trace);
|
log.info("write(trace): {}", trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.common.writer;
|
package datadog.trace.common.writer;
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan;
|
import datadog.opentracing.DDSpan;
|
||||||
import datadog.trace.common.DDTraceConfig;
|
import datadog.trace.common.DDTraceConfig;
|
||||||
import datadog.trace.common.Service;
|
import datadog.trace.common.Service;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -18,7 +18,7 @@ public interface Writer {
|
||||||
*
|
*
|
||||||
* @param trace the list of spans to write
|
* @param trace the list of spans to write
|
||||||
*/
|
*/
|
||||||
void write(List<DDBaseSpan<?>> trace);
|
void write(List<DDSpan> trace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report additional service information to the endpoint
|
* Report additional service information to the endpoint
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
package datadog.trace
|
|
||||||
|
|
||||||
import datadog.opentracing.DDTracer
|
|
||||||
import datadog.trace.common.writer.ListWriter
|
|
||||||
import io.opentracing.util.ThreadLocalActiveSpan
|
|
||||||
import spock.lang.Ignore
|
|
||||||
import spock.lang.Specification
|
|
||||||
|
|
||||||
import java.util.concurrent.Phaser
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
class ActiveSpanContinuationTest extends Specification {
|
|
||||||
|
|
||||||
def traceCollector = new ListWriter()
|
|
||||||
def tracer = new DDTracer(traceCollector)
|
|
||||||
def activeSpan = tracer.buildSpan("test").startActive()
|
|
||||||
AtomicInteger continuationCount
|
|
||||||
|
|
||||||
def setup() {
|
|
||||||
def field = ThreadLocalActiveSpan.getDeclaredField("refCount")
|
|
||||||
field.setAccessible(true)
|
|
||||||
continuationCount = field.get(activeSpan)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "calling activate from multiple continuations at once with no child spans tracks separately"() {
|
|
||||||
setup:
|
|
||||||
def phaser = new Phaser()
|
|
||||||
phaser.register()
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
phaser.register()
|
|
||||||
def capture = activeSpan.capture()
|
|
||||||
new Thread({
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
def activeSpan = capture.activate()
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
activeSpan.deactivate()
|
|
||||||
}).start()
|
|
||||||
}
|
|
||||||
|
|
||||||
activeSpan.deactivate() // allow the trace to be reported when all continuations deactivate
|
|
||||||
|
|
||||||
when:
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to activate capture
|
|
||||||
|
|
||||||
then:
|
|
||||||
traceCollector == []
|
|
||||||
|
|
||||||
when:
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to deactivate their span
|
|
||||||
|
|
||||||
then:
|
|
||||||
traceCollector.waitForTraces(1)
|
|
||||||
traceCollector.size() == 1
|
|
||||||
traceCollector.firstTrace().size() == 1
|
|
||||||
|
|
||||||
where:
|
|
||||||
count = new Random().nextInt(50) + 5
|
|
||||||
}
|
|
||||||
|
|
||||||
def "concurrent threads with manual spans and continuations report correctly"() {
|
|
||||||
setup:
|
|
||||||
def phaser = new Phaser()
|
|
||||||
phaser.register()
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
String spanName = "child " + i
|
|
||||||
phaser.register()
|
|
||||||
def capture = activeSpan.capture()
|
|
||||||
new Thread({
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
def activeSpan = capture.activate()
|
|
||||||
def childSpan = tracer.buildSpan(spanName).startManual()
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
childSpan.finish()
|
|
||||||
activeSpan.deactivate()
|
|
||||||
}).start()
|
|
||||||
}
|
|
||||||
|
|
||||||
expect:
|
|
||||||
continuationCount.get() == count + 1
|
|
||||||
|
|
||||||
when:
|
|
||||||
activeSpan.deactivate() // allow the trace to be reported when all continuations deactivate
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to activate capture
|
|
||||||
|
|
||||||
then:
|
|
||||||
continuationCount.get() == count
|
|
||||||
traceCollector == []
|
|
||||||
|
|
||||||
when:
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to deactivate their span
|
|
||||||
|
|
||||||
then:
|
|
||||||
traceCollector.waitForTraces(1)
|
|
||||||
continuationCount.get() == 0
|
|
||||||
traceCollector.size() == 1
|
|
||||||
def trace = traceCollector.remove(0)
|
|
||||||
def parent = trace.remove(0)
|
|
||||||
|
|
||||||
trace.size() == count
|
|
||||||
parent.context.parentId == 0
|
|
||||||
|
|
||||||
trace.every {
|
|
||||||
it.context.parentId == parent.context.spanId
|
|
||||||
}
|
|
||||||
|
|
||||||
where:
|
|
||||||
count = new Random().nextInt(50) + 5
|
|
||||||
}
|
|
||||||
|
|
||||||
def "concurrent threads with active spans and continuations report correctly"() {
|
|
||||||
setup:
|
|
||||||
def phaser = new Phaser()
|
|
||||||
phaser.register()
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
String spanName = "child " + i
|
|
||||||
phaser.register()
|
|
||||||
def capture = activeSpan.capture()
|
|
||||||
new Thread({
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
def activeSpan = capture.activate()
|
|
||||||
def childSpan = tracer.buildSpan(spanName).startActive()
|
|
||||||
phaser.arriveAndAwaitAdvance()
|
|
||||||
childSpan.deactivate()
|
|
||||||
activeSpan.deactivate()
|
|
||||||
phaser.arriveAndDeregister()
|
|
||||||
}).start()
|
|
||||||
}
|
|
||||||
|
|
||||||
expect:
|
|
||||||
continuationCount.get() == count + 1
|
|
||||||
|
|
||||||
when:
|
|
||||||
activeSpan.deactivate() // allow the trace to be reported when all continuations deactivate
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to activate capture
|
|
||||||
|
|
||||||
then:
|
|
||||||
continuationCount.get() == count
|
|
||||||
traceCollector == []
|
|
||||||
|
|
||||||
when:
|
|
||||||
phaser.arriveAndAwaitAdvance() //allow threads to deactivate their span
|
|
||||||
phaser.arriveAndAwaitAdvance() // wait till all threads have deactivated
|
|
||||||
|
|
||||||
then:
|
|
||||||
traceCollector.waitForTraces(1)
|
|
||||||
continuationCount.get() == 0
|
|
||||||
traceCollector.size() == 1
|
|
||||||
def trace = traceCollector.remove(0)
|
|
||||||
def parent = trace.remove(0)
|
|
||||||
|
|
||||||
trace.size() == count
|
|
||||||
parent.context.parentId == 0
|
|
||||||
|
|
||||||
trace.every {
|
|
||||||
it.context.parentId == parent.context.spanId
|
|
||||||
}
|
|
||||||
|
|
||||||
where:
|
|
||||||
count = new Random().nextInt(50) + 5
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Not yet implemented in ThreadLocalActiveSpan.Continuation")
|
|
||||||
def "calling activate more than once results in an error"() {
|
|
||||||
setup:
|
|
||||||
def capture = activeSpan.capture()
|
|
||||||
|
|
||||||
when:
|
|
||||||
activeSpan.deactivate()
|
|
||||||
|
|
||||||
then:
|
|
||||||
traceCollector == []
|
|
||||||
|
|
||||||
when:
|
|
||||||
capture.activate().deactivate()
|
|
||||||
// parent span should be finished at this point.
|
|
||||||
then:
|
|
||||||
traceCollector == []
|
|
||||||
|
|
||||||
when:
|
|
||||||
capture.activate().deactivate()
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown(RuntimeException)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
package datadog.trace.api.writer
|
package datadog.trace.api.writer
|
||||||
|
|
||||||
import datadog.opentracing.DDBaseSpan
|
import datadog.opentracing.DDSpan
|
||||||
import datadog.trace.common.writer.DDAgentWriter
|
import datadog.trace.common.writer.DDAgentWriter
|
||||||
import datadog.trace.common.writer.DDApi
|
import datadog.trace.common.writer.DDApi
|
||||||
import datadog.trace.common.writer.WriterQueue
|
import datadog.trace.common.writer.WriterQueue
|
||||||
|
@ -46,7 +46,7 @@ class DDAgentWriterTest extends Specification {
|
||||||
def "check if trace has been added by force"() {
|
def "check if trace has been added by force"() {
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
def traces = new WriterQueue<List<DDBaseSpan<?>>>(capacity)
|
def traces = new WriterQueue<List<DDSpan>>(capacity)
|
||||||
def writer = new DDAgentWriter(Mock(DDApi), traces)
|
def writer = new DDAgentWriter(Mock(DDApi), traces)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class DDTracerTest {
|
||||||
// Rate 0.5
|
// Rate 0.5
|
||||||
when(sampler.sample(any(DDSpan.class))).thenReturn(true).thenReturn(false);
|
when(sampler.sample(any(DDSpan.class))).thenReturn(true).thenReturn(false);
|
||||||
|
|
||||||
final Queue<DDBaseSpan<?>> spans = new LinkedList<>();
|
final Queue<DDSpan> spans = new LinkedList<>();
|
||||||
spans.add(span);
|
spans.add(span);
|
||||||
spans.add(span);
|
spans.add(span);
|
||||||
spans.add(span);
|
spans.add(span);
|
||||||
|
|
|
@ -6,9 +6,9 @@ import datadog.opentracing.DDTracer;
|
||||||
import datadog.opentracing.decorators.AbstractDecorator;
|
import datadog.opentracing.decorators.AbstractDecorator;
|
||||||
import datadog.opentracing.decorators.HTTPComponent;
|
import datadog.opentracing.decorators.HTTPComponent;
|
||||||
import datadog.opentracing.decorators.URLAsResourceName;
|
import datadog.opentracing.decorators.URLAsResourceName;
|
||||||
import io.opentracing.NoopTracerFactory;
|
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import io.opentracing.contrib.tracerresolver.TracerResolver;
|
import io.opentracing.contrib.tracerresolver.TracerResolver;
|
||||||
|
import io.opentracing.noop.NoopTracerFactory;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package datadog.example.dropwizard.client;
|
||||||
|
|
||||||
import datadog.trace.api.DDTags;
|
import datadog.trace.api.DDTags;
|
||||||
import datadog.trace.api.Trace;
|
import datadog.trace.api.Trace;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -25,8 +25,8 @@ public class TracedClient {
|
||||||
@Trace
|
@Trace
|
||||||
private static void executeCall() throws IOException {
|
private static void executeCall() throws IOException {
|
||||||
final Tracer tracer = GlobalTracer.get();
|
final Tracer tracer = GlobalTracer.get();
|
||||||
final ActiveSpan activeSpan = tracer.activeSpan();
|
final Scope scope = tracer.scopeManager().active();
|
||||||
activeSpan.setTag(DDTags.SERVICE_NAME, "http.client");
|
scope.span().setTag(DDTags.SERVICE_NAME, "http.client");
|
||||||
|
|
||||||
final OkHttpClient client = new OkHttpClient().newBuilder().build();
|
final OkHttpClient client = new OkHttpClient().newBuilder().build();
|
||||||
final Request request = new Request.Builder().url("http://localhost:8080/demo/").build();
|
final Request request = new Request.Builder().url("http://localhost:8080/demo/").build();
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.mongodb.client.MongoCursor;
|
||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
import datadog.example.dropwizard.api.Book;
|
import datadog.example.dropwizard.api.Book;
|
||||||
import datadog.trace.api.Trace;
|
import datadog.trace.api.Trace;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.util.GlobalTracer;
|
import io.opentracing.util.GlobalTracer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -113,9 +113,9 @@ public class SimpleCrudResource {
|
||||||
*/
|
*/
|
||||||
@Trace(operationName = "database.before")
|
@Trace(operationName = "database.before")
|
||||||
public void beforeDB() throws InterruptedException {
|
public void beforeDB() throws InterruptedException {
|
||||||
final ActiveSpan currentSpan = GlobalTracer.get().activeSpan();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (currentSpan != null) {
|
if (scope != null) {
|
||||||
currentSpan.setTag("status", "started");
|
scope.span().setTag("status", "started");
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,9 +127,9 @@ public class SimpleCrudResource {
|
||||||
*/
|
*/
|
||||||
@Trace(operationName = "database.after")
|
@Trace(operationName = "database.after")
|
||||||
public void afterDB() throws InterruptedException {
|
public void afterDB() throws InterruptedException {
|
||||||
final ActiveSpan currentSpan = GlobalTracer.get().activeSpan();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (currentSpan != null) {
|
if (scope != null) {
|
||||||
currentSpan.setTag("status", "started");
|
scope.span().setTag("status", "started");
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import static spark.Spark.get;
|
||||||
|
|
||||||
import com.mongodb.client.MongoCollection;
|
import com.mongodb.client.MongoCollection;
|
||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
import io.opentracing.ActiveSpan;
|
import io.opentracing.Scope;
|
||||||
import io.opentracing.Tracer;
|
import io.opentracing.Tracer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
@ -25,7 +25,7 @@ public class SparkApplication {
|
||||||
get(
|
get(
|
||||||
"/key/:id",
|
"/key/:id",
|
||||||
(req, res) -> {
|
(req, res) -> {
|
||||||
try (ActiveSpan activeSpan = mTracer.buildSpan("spark.request").startActive()) {
|
try (Scope scope = mTracer.buildSpan("spark.request").startActive(true)) {
|
||||||
final String id = req.params(":id");
|
final String id = req.params(":id");
|
||||||
|
|
||||||
// create a collection
|
// create a collection
|
||||||
|
@ -43,8 +43,8 @@ public class SparkApplication {
|
||||||
System.out.println(collection.count());
|
System.out.println(collection.count());
|
||||||
|
|
||||||
// add some metadata to the request Span
|
// add some metadata to the request Span
|
||||||
activeSpan.setTag("http.status_code", res.status());
|
scope.span().setTag("http.status_code", res.status());
|
||||||
activeSpan.setTag("http.url", req.url());
|
scope.span().setTag("http.url", req.url());
|
||||||
|
|
||||||
return "Stored!";
|
return "Stored!";
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,11 @@ public class SparkApplication {
|
||||||
get(
|
get(
|
||||||
"/users/:id",
|
"/users/:id",
|
||||||
(req, res) -> {
|
(req, res) -> {
|
||||||
try (ActiveSpan activeSpan = mTracer.buildSpan("spark.request").startActive()) {
|
try (Scope scope = mTracer.buildSpan("spark.request").startActive(true)) {
|
||||||
// this endpoint tests the 404 decorator
|
// this endpoint tests the 404 decorator
|
||||||
res.status(404);
|
res.status(404);
|
||||||
activeSpan.setTag("http.status_code", res.status());
|
scope.span().setTag("http.status_code", res.status());
|
||||||
activeSpan.setTag("http.url", req.url());
|
scope.span().setTag("http.url", req.url());
|
||||||
}
|
}
|
||||||
return "404";
|
return "404";
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ def spockGroovyVer = GroovySystem.version.replaceAll(/\.\d+$/, '')
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
version = [
|
version = [
|
||||||
opentracing: '0.30.0',
|
opentracing: '0.31.0',
|
||||||
|
|
||||||
slf4j : "1.7.25",
|
slf4j : "1.7.25",
|
||||||
guava : "23.0",
|
guava : "23.0",
|
||||||
|
|
Loading…
Reference in New Issue