diff --git a/dd-java-agent/agent-jmxfetch/agent-jmxfetch.gradle b/dd-java-agent/agent-jmxfetch/agent-jmxfetch.gradle index c075f69f72..b2f5f55862 100644 --- a/dd-java-agent/agent-jmxfetch/agent-jmxfetch.gradle +++ b/dd-java-agent/agent-jmxfetch/agent-jmxfetch.gradle @@ -4,7 +4,7 @@ plugins { apply from: "${rootDir}/gradle/java.gradle" dependencies { - compile('com.datadoghq:jmxfetch:0.29.0'){ + compile('com.datadoghq:jmxfetch:0.30.0'){ exclude group: 'org.slf4j', module: 'slf4j-log4j12' exclude group: 'log4j', module: 'log4j' } diff --git a/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java b/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java index 321e626314..b432aba41b 100644 --- a/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java +++ b/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java @@ -74,6 +74,8 @@ public class JMXFetch { final AppConfig.AppConfigBuilder configBuilder = AppConfig.builder() .action(ImmutableList.of(ACTION_COLLECT)) + // App should be run as daemon otherwise CLI apps would not exit once main method exits. + .daemon(true) .confdDirectory(jmxFetchConfigDir) .yamlFileList(jmxFetchConfigs) .targetDirectInstances(true) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java index 59c05548f9..d8275b233a 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java @@ -95,7 +95,7 @@ public class ClassLoaderMatcher { /** * TODO: this turns out to be useless with OSGi: {@code - * }org.eclipse.osgi.internal.loader.BundleLoader#isRequestFromVM} returns {@code true} when + * org.eclipse.osgi.internal.loader.BundleLoader#isRequestFromVM} returns {@code true} when * class loading is issued from this check and {@code false} for 'real' class loads. We should * come up with some sort of hack to avoid this problem. */ diff --git a/dd-java-agent/instrumentation/couchbase-2.0/src/test/groovy/util/AbstractCouchbaseTest.groovy b/dd-java-agent/instrumentation/couchbase-2.0/src/test/groovy/util/AbstractCouchbaseTest.groovy index 9d25162423..b5e3f25087 100644 --- a/dd-java-agent/instrumentation/couchbase-2.0/src/test/groovy/util/AbstractCouchbaseTest.groovy +++ b/dd-java-agent/instrumentation/couchbase-2.0/src/test/groovy/util/AbstractCouchbaseTest.groovy @@ -16,6 +16,7 @@ import com.couchbase.mock.CouchbaseMock import com.couchbase.mock.http.query.QueryServer import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.utils.PortUtils +import datadog.trace.api.Config import spock.lang.Shared import java.util.concurrent.RejectedExecutionException @@ -87,6 +88,9 @@ abstract class AbstractCouchbaseTest extends AgentTestRunner { // Cache buckets: couchbaseCluster.openBucket(bucketCouchbase.name(), bucketCouchbase.password()) memcacheCluster.openBucket(bucketMemcache.name(), bucketMemcache.password()) + + // This setting should have no effect since decorator returns null for the instance. + System.setProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "true") } private static BucketConfiguration convert(BucketSettings bucketSettings) { @@ -112,6 +116,8 @@ abstract class AbstractCouchbaseTest extends AgentTestRunner { } mock?.stop() + + System.clearProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE) } private DefaultCouchbaseEnvironment.Builder envBuilder(BucketSettings bucketSettings) { diff --git a/dd-java-agent/instrumentation/datastax-cassandra-3/src/test/groovy/CassandraClientTest.groovy b/dd-java-agent/instrumentation/datastax-cassandra-3/src/test/groovy/CassandraClientTest.groovy index 18968c1ea1..007d00cfb6 100644 --- a/dd-java-agent/instrumentation/datastax-cassandra-3/src/test/groovy/CassandraClientTest.groovy +++ b/dd-java-agent/instrumentation/datastax-cassandra-3/src/test/groovy/CassandraClientTest.groovy @@ -3,11 +3,13 @@ import com.datastax.driver.core.Session import datadog.opentracing.DDSpan import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.asserts.TraceAssert +import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags import org.cassandraunit.utils.EmbeddedCassandraServerHelper import spock.lang.Shared +import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride import static datadog.trace.agent.test.utils.TraceUtils.basicSpan import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace @@ -44,17 +46,19 @@ class CassandraClientTest extends AgentTestRunner { setup: Session session = cluster.connect(keyspace) - session.execute(statement) + withConfigOverride(Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "$renameService") { + session.execute(statement) + } expect: assertTraces(keyspace ? 2 : 1) { if (keyspace) { trace(0, 1) { - cassandraSpan(it, 0, "USE $keyspace", null) + cassandraSpan(it, 0, "USE $keyspace", null, false) } } trace(keyspace ? 1 : 0, 1) { - cassandraSpan(it, 0, statement, keyspace) + cassandraSpan(it, 0, statement, keyspace, renameService) } } @@ -62,19 +66,21 @@ class CassandraClientTest extends AgentTestRunner { session.close() where: - statement | keyspace - "DROP KEYSPACE IF EXISTS sync_test" | null - "CREATE KEYSPACE sync_test WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':3}" | null - "CREATE TABLE sync_test.users ( id UUID PRIMARY KEY, name text )" | "sync_test" - "INSERT INTO sync_test.users (id, name) values (uuid(), 'alice')" | "sync_test" - "SELECT * FROM users where name = 'alice' ALLOW FILTERING" | "sync_test" + statement | keyspace | renameService + "DROP KEYSPACE IF EXISTS sync_test" | null | false + "CREATE KEYSPACE sync_test WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':3}" | null | true + "CREATE TABLE sync_test.users ( id UUID PRIMARY KEY, name text )" | "sync_test" | false + "INSERT INTO sync_test.users (id, name) values (uuid(), 'alice')" | "sync_test" | false + "SELECT * FROM users where name = 'alice' ALLOW FILTERING" | "sync_test" | true } def "test async"() { setup: Session session = cluster.connect(keyspace) runUnderTrace("parent") { - session.executeAsync(statement) + withConfigOverride(Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "$renameService") { + session.executeAsync(statement) + } blockUntilChildSpansFinished(1) } @@ -82,12 +88,12 @@ class CassandraClientTest extends AgentTestRunner { assertTraces(keyspace ? 2 : 1) { if (keyspace) { trace(0, 1) { - cassandraSpan(it, 0, "USE $keyspace", null) + cassandraSpan(it, 0, "USE $keyspace", null, false) } } trace(keyspace ? 1 : 0, 2) { basicSpan(it, 0, "parent") - cassandraSpan(it, 1, statement, keyspace, span(0)) + cassandraSpan(it, 1, statement, keyspace, renameService, span(0)) } } @@ -95,17 +101,17 @@ class CassandraClientTest extends AgentTestRunner { session.close() where: - statement | keyspace - "DROP KEYSPACE IF EXISTS async_test" | null - "CREATE KEYSPACE async_test WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':3}" | null - "CREATE TABLE async_test.users ( id UUID PRIMARY KEY, name text )" | "async_test" - "INSERT INTO async_test.users (id, name) values (uuid(), 'alice')" | "async_test" - "SELECT * FROM users where name = 'alice' ALLOW FILTERING" | "async_test" + statement | keyspace | renameService + "DROP KEYSPACE IF EXISTS async_test" | null | false + "CREATE KEYSPACE async_test WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':3}" | null | true + "CREATE TABLE async_test.users ( id UUID PRIMARY KEY, name text )" | "async_test" | false + "INSERT INTO async_test.users (id, name) values (uuid(), 'alice')" | "async_test" | false + "SELECT * FROM users where name = 'alice' ALLOW FILTERING" | "async_test" | true } - def cassandraSpan(TraceAssert trace, int index, String statement, String keyspace, Object parentSpan = null, Throwable exception = null) { + def cassandraSpan(TraceAssert trace, int index, String statement, String keyspace, boolean renameService, Object parentSpan = null, Throwable exception = null) { trace.span(index) { - serviceName "cassandra" + serviceName renameService && keyspace ? keyspace : "cassandra" operationName "cassandra.query" resourceName statement spanType DDSpanTypes.CASSANDRA diff --git a/dd-java-agent/instrumentation/google-http-client/google-http-client.gradle b/dd-java-agent/instrumentation/google-http-client/google-http-client.gradle new file mode 100644 index 0000000000..b2631fab38 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/google-http-client.gradle @@ -0,0 +1,34 @@ +muzzle { + pass { + group = "com.google.http-client" + module = "google-http-client" + + // 1.19.0 is the first release. The versions before are betas and RCs + versions = "[1.19.0,)" + } +} + +apply from: "${rootDir}/gradle/java.gradle" +apply plugin: 'org.unbroken-dome.test-sets' + +testSets { + latestDepTest { + dirName = 'test' + } +} + +dependencies { + compileOnly group: 'com.google.http-client', name: 'google-http-client', version: '1.19.0' + + compile project(':dd-java-agent:agent-tooling') + + compile deps.bytebuddy + compile deps.opentracing + annotationProcessor deps.autoservice + implementation deps.autoservice + + testCompile project(':dd-java-agent:testing') + testCompile group: 'com.google.http-client', name: 'google-http-client', version: '1.19.0' + + latestDepTestCompile group: 'com.google.http-client', name: 'google-http-client', version: '+' +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientDecorator.java b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientDecorator.java new file mode 100644 index 0000000000..4a6d03c1e5 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientDecorator.java @@ -0,0 +1,50 @@ +package datadog.trace.instrumentation.googlehttpclient; + +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpResponse; +import datadog.trace.agent.decorator.HttpClientDecorator; +import java.net.URI; +import java.net.URISyntaxException; + +public class GoogleHttpClientDecorator extends HttpClientDecorator { + public static final GoogleHttpClientDecorator DECORATE = new GoogleHttpClientDecorator(); + + @Override + protected String method(final HttpRequest httpRequest) { + return httpRequest.getRequestMethod(); + } + + @Override + protected URI url(final HttpRequest httpRequest) throws URISyntaxException { + // Google uses %20 (space) instead of "+" for spaces in the fragment + // Add "+" back for consistency with the other http client instrumentations + final String url = httpRequest.getUrl().build(); + final String fixedUrl = url.replaceAll("%20", "+"); + return new URI(fixedUrl); + } + + @Override + protected String hostname(final HttpRequest httpRequest) { + return httpRequest.getUrl().getHost(); + } + + @Override + protected Integer port(final HttpRequest httpRequest) { + return httpRequest.getUrl().getPort(); + } + + @Override + protected Integer status(final HttpResponse httpResponse) { + return httpResponse.getStatusCode(); + } + + @Override + protected String[] instrumentationNames() { + return new String[] {"google-http-client"}; + } + + @Override + protected String component() { + return "google-http-client"; + } +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientInstrumentation.java b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientInstrumentation.java new file mode 100644 index 0000000000..d587ab0aba --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/GoogleHttpClientInstrumentation.java @@ -0,0 +1,193 @@ +package datadog.trace.instrumentation.googlehttpclient; + +import static datadog.trace.instrumentation.googlehttpclient.GoogleHttpClientDecorator.DECORATE; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpResponse; +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.bootstrap.ContextStore; +import datadog.trace.bootstrap.InstrumentationContext; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.log.Fields; +import io.opentracing.propagation.Format; +import io.opentracing.propagation.TextMap; +import io.opentracing.tag.Tags; +import io.opentracing.util.GlobalTracer; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public class GoogleHttpClientInstrumentation extends Instrumenter.Default { + public GoogleHttpClientInstrumentation() { + super("google-http-client"); + } + + @Override + public ElementMatcher typeMatcher() { + // HttpRequest is a final class. Only need to instrument it exactly + return named("com.google.api.client.http.HttpRequest"); + } + + @Override + public Map contextStore() { + return Collections.singletonMap( + "com.google.api.client.http.HttpRequest", RequestState.class.getName()); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.agent.decorator.BaseDecorator", + "datadog.trace.agent.decorator.ClientDecorator", + "datadog.trace.agent.decorator.HttpClientDecorator", + packageName + ".GoogleHttpClientDecorator", + packageName + ".RequestState", + getClass().getName() + "$GoogleHttpClientAdvice", + getClass().getName() + "$GoogleHttpClientAsyncAdvice", + getClass().getName() + "$HeadersInjectAdapter" + }; + } + + @Override + public Map, String> transformers() { + final Map, String> transformers = new HashMap<>(); + transformers.put( + isMethod().and(isPublic()).and(named("execute")).and(takesArguments(0)), + GoogleHttpClientAdvice.class.getName()); + + transformers.put( + isMethod() + .and(isPublic()) + .and(named("executeAsync")) + .and(takesArguments(1)) + .and(takesArgument(0, (named("java.util.concurrent.Executor")))), + GoogleHttpClientAsyncAdvice.class.getName()); + + return transformers; + } + + public static class GoogleHttpClientAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter(@Advice.This final HttpRequest request) { + + final ContextStore contextStore = + InstrumentationContext.get(HttpRequest.class, RequestState.class); + + RequestState state = contextStore.get(request); + + if (state == null) { + state = new RequestState(GlobalTracer.get().buildSpan("http.request").start()); + contextStore.put(request, state); + } + + final Span span = state.getSpan(); + + try (final Scope scope = GlobalTracer.get().scopeManager().activate(span, false)) { + DECORATE.afterStart(span); + DECORATE.onRequest(span, request); + GlobalTracer.get() + .inject(span.context(), Format.Builtin.HTTP_HEADERS, new HeadersInjectAdapter(request)); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.This final HttpRequest request, + @Advice.Return final HttpResponse response, + @Advice.Thrown final Throwable throwable) { + + final ContextStore contextStore = + InstrumentationContext.get(HttpRequest.class, RequestState.class); + final RequestState state = contextStore.get(request); + + if (state != null) { + final Span span = state.getSpan(); + + try (final Scope scope = GlobalTracer.get().scopeManager().activate(span, false)) { + DECORATE.onResponse(span, response); + DECORATE.onError(span, throwable); + + // If HttpRequest.setThrowExceptionOnExecuteError is set to false, there are no exceptions + // for a failed request. Thus, check the response code + if (response != null && !response.isSuccessStatusCode()) { + Tags.ERROR.set(span, true); + span.log(singletonMap(Fields.MESSAGE, response.getStatusMessage())); + } + + DECORATE.beforeFinish(span); + span.finish(); + } + } + } + } + + public static class GoogleHttpClientAsyncAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter(@Advice.This final HttpRequest request) { + final Span span = GlobalTracer.get().buildSpan("http.request").start(); + + final ContextStore contextStore = + InstrumentationContext.get(HttpRequest.class, RequestState.class); + + final RequestState state = new RequestState(span); + contextStore.put(request, state); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.This final HttpRequest request, @Advice.Thrown final Throwable throwable) { + + if (throwable != null) { + + final ContextStore contextStore = + InstrumentationContext.get(HttpRequest.class, RequestState.class); + final RequestState state = contextStore.get(request); + + if (state != null) { + final Span span = state.getSpan(); + + try (final Scope scope = GlobalTracer.get().scopeManager().activate(span, false)) { + DECORATE.onError(span, throwable); + + DECORATE.beforeFinish(span); + span.finish(); + } + } + } + } + } + + public static class HeadersInjectAdapter implements TextMap { + private final HttpRequest request; + + public HeadersInjectAdapter(final HttpRequest request) { + this.request = request; + } + + @Override + public Iterator> iterator() { + throw new UnsupportedOperationException( + "This class should be used only with tracer#inject()"); + } + + @Override + public void put(final String key, final String value) { + request.getHeaders().put(key, value); + } + } +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/RequestState.java b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/RequestState.java new file mode 100644 index 0000000000..8e52df3b72 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/main/java/datadog/trace/instrumentation/googlehttpclient/RequestState.java @@ -0,0 +1,10 @@ +package datadog.trace.instrumentation.googlehttpclient; + +import io.opentracing.Span; +import lombok.Data; +import lombok.NonNull; + +@Data +public class RequestState { + @NonNull public Span span; +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/test/groovy/AbstractGoogleHttpClientTest.groovy b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/AbstractGoogleHttpClientTest.groovy new file mode 100644 index 0000000000..d255ed2642 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/AbstractGoogleHttpClientTest.groovy @@ -0,0 +1,69 @@ +import com.google.api.client.http.GenericUrl +import com.google.api.client.http.HttpRequest +import com.google.api.client.http.HttpResponse +import com.google.api.client.http.javanet.NetHttpTransport +import datadog.trace.agent.test.base.HttpClientTest +import datadog.trace.api.DDSpanTypes +import datadog.trace.instrumentation.googlehttpclient.GoogleHttpClientDecorator +import spock.lang.Shared + +abstract class AbstractGoogleHttpClientTest extends HttpClientTest { + + @Shared + def requestFactory = new NetHttpTransport().createRequestFactory() + + @Override + int doRequest(String method, URI uri, Map headers, Closure callback) { + doRequest(method, uri, headers, callback, false) + } + + int doRequest(String method, URI uri, Map headers, Closure callback, boolean throwExceptionOnError) { + GenericUrl genericUrl = new GenericUrl(uri) + + HttpRequest request = requestFactory.buildRequest(method, genericUrl, null) + request.getHeaders().putAll(headers) + request.setThrowExceptionOnExecuteError(throwExceptionOnError) + + HttpResponse response = executeRequest(request) + callback?.call() + + return response.getStatusCode() + } + + abstract HttpResponse executeRequest(HttpRequest request) + + @Override + GoogleHttpClientDecorator decorator() { + return GoogleHttpClientDecorator.DECORATE + } + + @Override + boolean testRedirects() { + // Circular redirects don't throw an exception with Google Http Client + return false + } + + def "error traces when exception is not thrown"() { + given: + def uri = server.address.resolve("/error") + + when: + def status = doRequest(method, uri) + + then: + status == 500 + assertTraces(2) { + server.distributedRequestTrace(it, 0, trace(1).last()) + trace(1, size(1)) { + span(0) { + resourceName "$method $uri.path" + spanType DDSpanTypes.HTTP_CLIENT + errored true + } + } + } + + where: + method = "GET" + } +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientAsyncTest.groovy b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientAsyncTest.groovy new file mode 100644 index 0000000000..934e31dc54 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientAsyncTest.groovy @@ -0,0 +1,9 @@ +import com.google.api.client.http.HttpRequest +import com.google.api.client.http.HttpResponse + +class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest { + @Override + HttpResponse executeRequest(HttpRequest request) { + return request.executeAsync().get() + } +} diff --git a/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientTest.groovy b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientTest.groovy new file mode 100644 index 0000000000..b9ef46ac67 --- /dev/null +++ b/dd-java-agent/instrumentation/google-http-client/src/test/groovy/GoogleHttpClientTest.groovy @@ -0,0 +1,9 @@ +import com.google.api.client.http.HttpRequest +import com.google.api.client.http.HttpResponse + +class GoogleHttpClientTest extends AbstractGoogleHttpClientTest { + @Override + HttpResponse executeRequest(HttpRequest request) { + return request.execute() + } +} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java index 8f5124ad79..a8000ba357 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -295,7 +295,6 @@ public enum JDBCConnectionUrlParser { MSSQLSERVER("microsoft", "sqlserver") { private static final String DEFAULT_HOST = "localhost"; private static final int DEFAULT_PORT = 1433; - private static final String DEFAULT_INSTANCE = "MSSQLSERVER"; @Override DBInfo.Builder doParse(String jdbcUrl, final DBInfo.Builder builder) { @@ -307,9 +306,6 @@ public enum JDBCConnectionUrlParser { } builder.type("sqlserver"); final DBInfo dbInfo = builder.build(); - if (dbInfo.getInstance() == null) { - builder.instance(DEFAULT_INSTANCE); - } if (dbInfo.getHost() == null) { builder.host(DEFAULT_HOST); } diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy index e0fb31854a..b3a662ef55 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCConnectionUrlParserTest.groovy @@ -88,12 +88,12 @@ class JDBCConnectionUrlParserTest extends Specification { "address=(host=anotherhost)(port=3306)(user=wrong)(password=PW)/mdbdb?user=mdbuser&password=PW" | null | "mysql" | "replication" | "mdbuser" | "mdb.host" | 3306 | null | "mdbdb" //https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url - "jdbc:microsoft:sqlserver://;" | null | "sqlserver" | null | null | "localhost" | 1433 | "MSSQLSERVER" | null - "jdbc:microsoft:sqlserver://;" | stdProps | "sqlserver" | null | "stdUserName" | "stdServerName" | 9999 | "MSSQLSERVER" | "stdDatabaseName" + "jdbc:microsoft:sqlserver://;" | null | "sqlserver" | null | null | "localhost" | 1433 | null | null + "jdbc:microsoft:sqlserver://;" | stdProps | "sqlserver" | null | "stdUserName" | "stdServerName" | 9999 | null | "stdDatabaseName" "jdbc:sqlserver://ss.host\\ssinstance:44;databaseName=ssdb;user=ssuser;password=pw" | null | "sqlserver" | null | "ssuser" | "ss.host" | 44 | "ssinstance" | "ssdb" "jdbc:sqlserver://;serverName=ss.host\\ssinstance:44;DatabaseName=;" | null | "sqlserver" | null | null | "ss.host" | 44 | "ssinstance" | null - "jdbc:sqlserver://ss.host;serverName=althost;DatabaseName=ssdb;" | null | "sqlserver" | null | null | "ss.host" | 1433 | "MSSQLSERVER" | "ssdb" - "jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | null | "sqlserver" | null | "ssuser" | "ss.host" | 44 | "MSSQLSERVER" | "ssdb" + "jdbc:sqlserver://ss.host;serverName=althost;DatabaseName=ssdb;" | null | "sqlserver" | null | null | "ss.host" | 1433 | null | "ssdb" + "jdbc:microsoft:sqlserver://ss.host:44;DatabaseName=ssdb;user=ssuser;password=pw;user=ssuser2;" | null | "sqlserver" | null | "ssuser" | "ss.host" | 44 | null | "ssdb" // https://docs.oracle.com/cd/B28359_01/java.111/b31224/urls.htm // https://docs.oracle.com/cd/B28359_01/java.111/b31224/jdbcthin.htm diff --git a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy index 9ecc358c19..2211ae4458 100644 --- a/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy +++ b/dd-java-agent/instrumentation/jdbc/src/test/groovy/JDBCInstrumentationTest.groovy @@ -2,6 +2,7 @@ import com.mchange.v2.c3p0.ComboPooledDataSource import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags import javax.sql.DataSource @@ -17,6 +18,7 @@ import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.Statement +import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace class JDBCInstrumentationTest extends AgentTestRunner { @@ -154,7 +156,9 @@ class JDBCInstrumentationTest extends AgentTestRunner { setup: Statement statement = connection.createStatement() ResultSet resultSet = runUnderTrace("parent") { - return statement.executeQuery(query) + withConfigOverride(Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "$renameService") { + return statement.executeQuery(query) + } } expect: @@ -167,8 +171,8 @@ class JDBCInstrumentationTest extends AgentTestRunner { parent() } span(1) { + serviceName renameService ? dbName.toLowerCase() : driver operationName "${driver}.query" - serviceName driver resourceName query spanType DDSpanTypes.SQL childOf span(0) @@ -193,22 +197,22 @@ class JDBCInstrumentationTest extends AgentTestRunner { connection.close() where: - driver | connection | username | query - "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | "SELECT 3" - "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" - "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | "SELECT 3" - "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | "SELECT 3 FROM SYSIBM.SYSDUMMY1" - "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + driver | connection | username | renameService | query + "h2" | new Driver().connect(jdbcUrls.get("h2"), null) | null | false | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), null) | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), null) | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | new Driver().connect(jdbcUrls.get("h2"), connectionProps) | null | true | "SELECT 3" + "derby" | new EmbeddedDriver().connect(jdbcUrls.get("derby"), connectionProps) | "APP" | true | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | new JDBCDriver().connect(jdbcUrls.get("hsqldb"), connectionProps) | "SA" | true | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("tomcat").get("h2").getConnection() | null | false | "SELECT 3" + "derby" | cpDatasources.get("tomcat").get("derby").getConnection() | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("tomcat").get("hsqldb").getConnection() | "SA" | true | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("hikari").get("h2").getConnection() | null | false | "SELECT 3" + "derby" | cpDatasources.get("hikari").get("derby").getConnection() | "APP" | true | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("hikari").get("hsqldb").getConnection() | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" + "h2" | cpDatasources.get("c3p0").get("h2").getConnection() | null | true | "SELECT 3" + "derby" | cpDatasources.get("c3p0").get("derby").getConnection() | "APP" | false | "SELECT 3 FROM SYSIBM.SYSDUMMY1" + "hsqldb" | cpDatasources.get("c3p0").get("hsqldb").getConnection() | "SA" | false | "SELECT 3 FROM INFORMATION_SCHEMA.SYSTEM_USERS" } @Unroll diff --git a/dd-java-agent/instrumentation/jedis-1.4/src/test/groovy/JedisClientTest.groovy b/dd-java-agent/instrumentation/jedis-1.4/src/test/groovy/JedisClientTest.groovy index a28d642a2a..42041c647b 100644 --- a/dd-java-agent/instrumentation/jedis-1.4/src/test/groovy/JedisClientTest.groovy +++ b/dd-java-agent/instrumentation/jedis-1.4/src/test/groovy/JedisClientTest.groovy @@ -1,4 +1,5 @@ import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags import redis.clients.jedis.Jedis @@ -22,11 +23,16 @@ class JedisClientTest extends AgentTestRunner { def setupSpec() { println "Using redis: $redisServer.args" redisServer.start() + + // This setting should have no effect since decorator returns null for the instance. + System.setProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "true") } def cleanupSpec() { redisServer.stop() // jedis.close() // not available in the early version we're using. + + System.clearProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE) } def setup() { diff --git a/dd-java-agent/instrumentation/jetty-8/jetty-8.gradle b/dd-java-agent/instrumentation/jetty-8/jetty-8.gradle index be5a2d8373..1a7c354b3c 100644 --- a/dd-java-agent/instrumentation/jetty-8/jetty-8.gradle +++ b/dd-java-agent/instrumentation/jetty-8/jetty-8.gradle @@ -34,7 +34,9 @@ dependencies { testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '8.0.0.v20110901' testCompile group: 'org.eclipse.jetty', name: 'jetty-continuation', version: '8.0.0.v20110901' - latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '+' - latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '+' - latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-continuation', version: '+' + // Jetty 10 seems to refuse to run on java8. + // TODO: we need to setup separate test for Jetty 10 when that is released. + latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' + latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.+' + latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-continuation', version: '9.+' } diff --git a/dd-java-agent/instrumentation/mongo/driver-3.1/src/test/groovy/MongoClientTest.groovy b/dd-java-agent/instrumentation/mongo/driver-3.1/src/test/groovy/MongoClientTest.groovy index 66ded8bb60..f21f85546f 100644 --- a/dd-java-agent/instrumentation/mongo/driver-3.1/src/test/groovy/MongoClientTest.groovy +++ b/dd-java-agent/instrumentation/mongo/driver-3.1/src/test/groovy/MongoClientTest.groovy @@ -6,6 +6,7 @@ import com.mongodb.client.MongoCollection import com.mongodb.client.MongoDatabase import datadog.opentracing.DDSpan import datadog.trace.agent.test.asserts.TraceAssert +import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags import org.bson.BsonDocument @@ -13,6 +14,7 @@ import org.bson.BsonString import org.bson.Document import spock.lang.Shared +import static datadog.trace.agent.test.utils.ConfigUtils.withConfigOverride import static datadog.trace.agent.test.utils.PortUtils.UNUSABLE_PORT import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace @@ -38,18 +40,21 @@ class MongoClientTest extends MongoBaseTest { MongoDatabase db = client.getDatabase(dbName) when: - db.createCollection(collectionName) + withConfigOverride(Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "$renameService") { + db.createCollection(collectionName) + } then: assertTraces(1) { trace(0, 1) { - mongoSpan(it, 0, "{\"create\":\"$collectionName\",\"capped\":\"?\"}") + mongoSpan(it, 0, "{\"create\":\"$collectionName\",\"capped\":\"?\"}", renameService) } } where: dbName = "test_db" collectionName = "testCollection" + renameService << [false, true] } def "test create collection no description"() { @@ -62,7 +67,7 @@ class MongoClientTest extends MongoBaseTest { then: assertTraces(1) { trace(0, 1) { - mongoSpan(it, 0, "{\"create\":\"$collectionName\",\"capped\":\"?\"}", dbName) + mongoSpan(it, 0, "{\"create\":\"$collectionName\",\"capped\":\"?\"}", false, dbName) } } @@ -228,9 +233,9 @@ class MongoClientTest extends MongoBaseTest { collectionName = "testCollection" } - def mongoSpan(TraceAssert trace, int index, String statement, String instance = "some-description", Object parentSpan = null, Throwable exception = null) { + def mongoSpan(TraceAssert trace, int index, String statement, boolean renameService = false, String instance = "some-description", Object parentSpan = null, Throwable exception = null) { trace.span(index) { - serviceName "mongo" + serviceName renameService ? instance : "mongo" operationName "mongo.query" resourceName { assert it.replace(" ", "") == statement diff --git a/dd-java-agent/instrumentation/servlet-3/servlet-3.gradle b/dd-java-agent/instrumentation/servlet-3/servlet-3.gradle index 3ce592b6c8..7ed27b3c41 100644 --- a/dd-java-agent/instrumentation/servlet-3/servlet-3.gradle +++ b/dd-java-agent/instrumentation/servlet-3/servlet-3.gradle @@ -41,8 +41,10 @@ dependencies { testCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.0.41' testCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '8.0.41' - latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '+' - latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '+' + // Jetty 10 seems to refuse to run on java8. + // TODO: we need to setup separate test for Jetty 10 when that is released. + latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.+' + latestDepTestCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.+' latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '+' latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '+' } diff --git a/dd-java-agent/instrumentation/spymemcached-2.12/src/test/groovy/datadog/trace/instrumentation/spymemcached/SpymemcachedTest.groovy b/dd-java-agent/instrumentation/spymemcached-2.12/src/test/groovy/datadog/trace/instrumentation/spymemcached/SpymemcachedTest.groovy index 2f02de169e..7fba808b7d 100644 --- a/dd-java-agent/instrumentation/spymemcached-2.12/src/test/groovy/datadog/trace/instrumentation/spymemcached/SpymemcachedTest.groovy +++ b/dd-java-agent/instrumentation/spymemcached-2.12/src/test/groovy/datadog/trace/instrumentation/spymemcached/SpymemcachedTest.groovy @@ -3,6 +3,7 @@ package datadog.trace.instrumentation.spymemcached import com.google.common.util.concurrent.MoreExecutors import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.asserts.TraceAssert +import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import io.opentracing.tag.Tags import net.spy.memcached.CASResponse @@ -71,12 +72,17 @@ class SpymemcachedTest extends AgentTestRunner { memcachedContainer.getMappedPort(defaultMemcachedPort) ) } + + // This setting should have no effect since decorator returns null for the instance. + System.setProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE, "true") } def cleanupSpec() { if (memcachedContainer) { memcachedContainer.stop() } + + System.clearProperty(Config.PREFIX + Config.DB_CLIENT_HOST_SPLIT_BY_INSTANCE) } ReentrantLock queueLock diff --git a/dd-trace-java.gradle b/dd-trace-java.gradle index 0de18a9544..16a39866f7 100644 --- a/dd-trace-java.gradle +++ b/dd-trace-java.gradle @@ -52,7 +52,6 @@ buildScan { wrapper { distributionType = Wrapper.DistributionType.ALL - version = '5.5.1' } allprojects { diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/ContainerInfo.java b/dd-trace-ot/src/main/java/datadog/opentracing/ContainerInfo.java new file mode 100644 index 0000000000..455bb34969 --- /dev/null +++ b/dd-trace-ot/src/main/java/datadog/opentracing/ContainerInfo.java @@ -0,0 +1,128 @@ +package datadog.opentracing; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * Parses container information from /proc/self/cgroup. Implementation based largely on + * Qard/container-info + */ +@Getter +@Setter +@Slf4j +public class ContainerInfo { + private static final Path CGROUP_DEFAULT_PROCFILE = Paths.get("/proc/self/cgroup"); + private static final String UUID_REGEX = + "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}"; + private static final String CONTAINER_REGEX = "[0-9a-f]{64}"; + private static final Pattern LINE_PATTERN = Pattern.compile("(\\d+):([^:]*):(.+)$"); + private static final Pattern POD_PATTERN = + Pattern.compile("(?:.+)?pod(" + UUID_REGEX + ")(?:.slice)?$"); + private static final Pattern CONTAINER_PATTERN = + Pattern.compile("(?:.+)?(" + UUID_REGEX + "|" + CONTAINER_REGEX + ")(?:.scope)?$"); + + private static final ContainerInfo INSTANCE; + + public String containerId; + public String podId; + public List cGroups = new ArrayList<>(); + + static { + ContainerInfo containerInfo = new ContainerInfo(); + if (ContainerInfo.isRunningInContainer()) { + try { + containerInfo = ContainerInfo.fromDefaultProcFile(); + } catch (final IOException | ParseException e) { + log.error("Unable to parse proc file"); + } + } + + INSTANCE = containerInfo; + } + + @Getter + @Setter + public static class CGroupInfo { + public int id; + public String path; + public List controllers; + public String containerId; + public String podId; + } + + public static ContainerInfo get() { + return INSTANCE; + } + + public static boolean isRunningInContainer() { + return Files.isReadable(CGROUP_DEFAULT_PROCFILE); + } + + public static ContainerInfo fromDefaultProcFile() throws IOException, ParseException { + final String content = new String(Files.readAllBytes(CGROUP_DEFAULT_PROCFILE)); + return parse(content); + } + + public static ContainerInfo parse(final String cgroupsContent) throws ParseException { + final ContainerInfo containerInfo = new ContainerInfo(); + + final String[] lines = cgroupsContent.split("\n"); + for (final String line : lines) { + final CGroupInfo cGroupInfo = parseLine(line); + + containerInfo.getCGroups().add(cGroupInfo); + + if (cGroupInfo.getPodId() != null) { + containerInfo.setPodId(cGroupInfo.getPodId()); + } + + if (cGroupInfo.getContainerId() != null) { + containerInfo.setContainerId(cGroupInfo.getContainerId()); + } + } + + return containerInfo; + } + + static CGroupInfo parseLine(final String line) throws ParseException { + final Matcher matcher = LINE_PATTERN.matcher(line); + + if (!matcher.matches()) { + throw new ParseException("Unable to match cgroup", 0); + } + + final CGroupInfo cGroupInfo = new CGroupInfo(); + cGroupInfo.setId(Integer.parseInt(matcher.group(1))); + cGroupInfo.setControllers(Arrays.asList(matcher.group(2).split(","))); + + final String path = matcher.group(3); + final String[] pathParts = path.split("/"); + + cGroupInfo.setPath(path); + + if (pathParts.length >= 1) { + final Matcher containerIdMatcher = CONTAINER_PATTERN.matcher(pathParts[pathParts.length - 1]); + final String containerId = containerIdMatcher.matches() ? containerIdMatcher.group(1) : null; + cGroupInfo.setContainerId(containerId); + } + + if (pathParts.length >= 2) { + final Matcher podIdMatcher = POD_PATTERN.matcher(pathParts[pathParts.length - 2]); + final String podId = podIdMatcher.matches() ? podIdMatcher.group(1) : null; + cGroupInfo.setPodId(podId); + } + + return cGroupInfo; + } +} diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/ContinuableScope.java b/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/ContinuableScope.java index a40126b343..049a14ad77 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/ContinuableScope.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/ContinuableScope.java @@ -44,6 +44,7 @@ public class ContinuableScope implements Scope, TraceScope { final Continuation continuation, final DDSpan spanUnderScope, final boolean finishOnClose) { + assert spanUnderScope != null : "span must not be null"; this.scopeManager = scopeManager; this.openCount = openCount; this.continuation = continuation; diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/SimpleScope.java b/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/SimpleScope.java index fc43e92fe8..3f97c8a2d7 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/SimpleScope.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/scopemanager/SimpleScope.java @@ -15,10 +15,11 @@ public class SimpleScope implements Scope { final ContextualScopeManager scopeManager, final Span spanUnderScope, final boolean finishOnClose) { + assert spanUnderScope != null : "span must not be null"; this.scopeManager = scopeManager; this.spanUnderScope = spanUnderScope; this.finishOnClose = finishOnClose; - this.toRestore = scopeManager.tlsScope.get(); + toRestore = scopeManager.tlsScope.get(); scopeManager.tlsScope.set(this); for (final ScopeListener listener : scopeManager.scopeListeners) { listener.afterScopeActivated(); diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDApi.java b/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDApi.java index 8fa1bd170a..e3acc6ed5b 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDApi.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDApi.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import datadog.opentracing.ContainerInfo; import datadog.opentracing.DDSpan; import datadog.opentracing.DDTraceOTInfo; import datadog.trace.common.writer.unixdomainsockets.UnixDomainSocketFactory; @@ -35,6 +36,7 @@ public class DDApi { private static final String DATADOG_META_LANG_INTERPRETER_VENDOR = "Datadog-Meta-Lang-Interpreter-Vendor"; private static final String DATADOG_META_TRACER_VERSION = "Datadog-Meta-Tracer-Version"; + private static final String DATADOG_CONTAINER_ID = "Datadog-Container-ID"; private static final String X_DATADOG_TRACE_COUNT = "X-Datadog-Trace-Count"; private static final int HTTP_TIMEOUT = 1; // 1 second for conenct/read/write operations @@ -261,13 +263,21 @@ public class DDApi { } private static Request.Builder prepareRequest(final HttpUrl url) { - return new Request.Builder() - .url(url) - .addHeader(DATADOG_META_LANG, "java") - .addHeader(DATADOG_META_LANG_VERSION, DDTraceOTInfo.JAVA_VERSION) - .addHeader(DATADOG_META_LANG_INTERPRETER, DDTraceOTInfo.JAVA_VM_NAME) - .addHeader(DATADOG_META_LANG_INTERPRETER_VENDOR, DDTraceOTInfo.JAVA_VM_VENDOR) - .addHeader(DATADOG_META_TRACER_VERSION, DDTraceOTInfo.VERSION); + final Request.Builder builder = + new Request.Builder() + .url(url) + .addHeader(DATADOG_META_LANG, "java") + .addHeader(DATADOG_META_LANG_VERSION, DDTraceOTInfo.JAVA_VERSION) + .addHeader(DATADOG_META_LANG_INTERPRETER, DDTraceOTInfo.JAVA_VM_NAME) + .addHeader(DATADOG_META_LANG_INTERPRETER_VENDOR, DDTraceOTInfo.JAVA_VM_VENDOR) + .addHeader(DATADOG_META_TRACER_VERSION, DDTraceOTInfo.VERSION); + + final String containerId = ContainerInfo.get().getContainerId(); + if (containerId == null) { + return builder; + } else { + return builder.addHeader(DATADOG_CONTAINER_ID, containerId); + } } @Override diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/ContainerInfoTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/ContainerInfoTest.groovy new file mode 100644 index 0000000000..051ab2c9c1 --- /dev/null +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/ContainerInfoTest.groovy @@ -0,0 +1,148 @@ +package datadog.opentracing + +import spock.lang.Specification +import spock.lang.Unroll + + +class ContainerInfoTest extends Specification { + + @Unroll + def "CGroupInfo is parsed from individual lines"() { + when: + ContainerInfo.CGroupInfo cGroupInfo = ContainerInfo.parseLine(line) + + then: + cGroupInfo.getId() == id + cGroupInfo.getPath() == path + cGroupInfo.getControllers() == controllers + cGroupInfo.getContainerId() == containerId + cGroupInfo.podId == podId + + // Examples from container tagging rfc and Qard/container-info + where: + id | controllers | path | containerId | podId | line + + // Docker examples + 13 | ["name=systemd"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 12 | ["pids"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "12:pids:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 11 | ["hugetlb"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "11:hugetlb:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 10 | ["net_prio"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "10:net_prio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 9 | ["perf_event"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "9:perf_event:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 8 | ["net_cls"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "8:net_cls:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 7 | ["freezer"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "7:freezer:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 6 | ["devices"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "6:devices:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 5 | ["memory"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "5:memory:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 4 | ["blkio"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "4:blkio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 3 | ["cpuacct"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "3:cpuacct:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 2 | ["cpu"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "2:cpu:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + 1 | ["cpuset"] | "/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | "1:cpuset:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" + + // Kubernates examples + 11 | ["perf_event"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "11:perf_event:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 10 | ["pids"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "10:pids:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 9 | ["memory"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "9:memory:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 8 | ["cpu", "cpuacct"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "8:cpu,cpuacct:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 7 | ["blkio"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "7:blkio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 6 | ["cpuset"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "6:cpuset:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 5 | ["devices"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "5:devices:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 4 | ["freezer"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "4:freezer:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 3 | ["net_cls", "net_prio"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "3:net_cls,net_prio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 2 | ["hugetlb"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "2:hugetlb:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + 1 | ["name=systemd"] | "/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | "1:name=systemd:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" + + //ECS examples + 9 | ["perf_event"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "9:perf_event:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 8 | ["memory"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "8:memory:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 7 | ["hugetlb"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "7:hugetlb:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 6 | ["freezer"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "6:freezer:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 5 | ["devices"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "5:devices:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 4 | ["cpuset"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "4:cpuset:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 3 | ["cpuacct"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "3:cpuacct:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 2 | ["cpu"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "2:cpu:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + 1 | ["blkio"] | "/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | "1:blkio:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" + + //Fargate Examples + 11 | ["hugetlb"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 10 | ["pids"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 9 | ["cpuset"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 8 | ["net_cls", "net_prio"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 7 | ["cpu", "cpuacct"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "7:cpu,cpuacct:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 6 | ["perf_event"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "6:perf_event:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 5 | ["freezer"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "5:freezer:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 4 | ["devices"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "4:devices:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 3 | ["blkio"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "3:blkio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 2 | ["memory"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + 1 | ["name=systemd"] | "/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | "1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" + + //Reference impl examples + 1 | ["name=systemd"] | "/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope" | "cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411" | null | "1:name=systemd:/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope" + 1 | ["name=systemd"] | "/docker/051e2ee0bce99116029a13df4a9e943137f19f957f38ac02d6bad96f9b700f76/not_hex" | null | null | "1:name=systemd:/docker/051e2ee0bce99116029a13df4a9e943137f19f957f38ac02d6bad96f9b700f76/not_hex" + 1 | ["name=systemd"] | "/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod90d81341_92de_11e7_8cf2_507b9d4141fa.slice/crio-2227daf62df6694645fee5df53c1f91271546a9560e8600a525690ae252b7f63.scope" | "2227daf62df6694645fee5df53c1f91271546a9560e8600a525690ae252b7f63" | "90d81341_92de_11e7_8cf2_507b9d4141fa" | "1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod90d81341_92de_11e7_8cf2_507b9d4141fa.slice/crio-2227daf62df6694645fee5df53c1f91271546a9560e8600a525690ae252b7f63.scope" + + } + + @Unroll + def "Container info parsed from file content"() { + when: + ContainerInfo containerInfo = ContainerInfo.parse(content) + + then: + containerInfo.getContainerId() == containerId + containerInfo.getPodId() == podId + containerInfo.getCGroups().size() == size + + where: + containerId | podId | size | content + // Docker + "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860" | null | 13 | """13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +12:pids:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +11:hugetlb:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +10:net_prio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +9:perf_event:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +8:net_cls:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +7:freezer:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +6:devices:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +5:memory:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +4:blkio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +3:cpuacct:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +2:cpu:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +1:cpuset:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860""" + + // Kubernetes + "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1" | "3d274242-8ee0-11e9-a8a6-1e68d864ef1a" | 11 | """11:perf_event:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +10:pids:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +9:memory:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +8:cpu,cpuacct:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +7:blkio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +6:cpuset:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +5:devices:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +4:freezer:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +3:net_cls,net_prio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +2:hugetlb:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +1:name=systemd:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1""" + + // ECS + "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce" | null | 9 | """9:perf_event:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +8:memory:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +7:hugetlb:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +6:freezer:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +5:devices:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +4:cpuset:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +3:cpuacct:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +2:cpu:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +1:blkio:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce""" + + // Fargate + "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da" | null | 11 | """11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +7:cpu,cpuacct:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +6:perf_event:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +5:freezer:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +4:devices:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +3:blkio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da""" + } +} diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy index f158c3845b..86452c433d 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy @@ -6,6 +6,8 @@ import datadog.trace.api.Config import datadog.trace.api.DDTags import datadog.trace.api.sampling.PrioritySampling import datadog.trace.common.writer.ListWriter +import io.opentracing.Scope +import io.opentracing.noop.NoopSpan import spock.lang.Specification import static datadog.opentracing.DDSpanContext.ORIGIN_KEY @@ -173,6 +175,33 @@ class DDSpanBuilderTest extends Specification { actualContext.getTraceId() == spanId } + def "should link to parent span implicitly"() { + setup: + final Scope parent = noopParent ? + tracer.scopeManager().activate(NoopSpan.INSTANCE, false) : + tracer.buildSpan("parent") + .startActive(false) + + final String expectedParentId = noopParent ? "0" : parent.span().context().getSpanId() + + final String expectedName = "fakeName" + + final DDSpan span = tracer + .buildSpan(expectedName) + .start() + + final DDSpanContext actualContext = span.context() + + expect: + actualContext.getParentId() == expectedParentId + + cleanup: + parent.close() + + where: + noopParent << [false, true] + } + def "should inherit the DD parent attributes"() { setup: def expectedName = "fakeName" diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/scopemanager/ScopeManagerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/scopemanager/ScopeManagerTest.groovy index 4ff52ea087..80e2eeb879 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/scopemanager/ScopeManagerTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/scopemanager/ScopeManagerTest.groovy @@ -96,19 +96,19 @@ class ScopeManagerTest extends Specification { def "sets parent as current upon close"() { setup: def parentScope = tracer.buildSpan("parent").startActive(finishSpan) - def childScope = tracer.buildSpan("parent").startActive(finishSpan) + def childScope = noopChild ? tracer.scopeManager().activate(NoopSpan.INSTANCE, finishSpan) : tracer.buildSpan("parent").startActive(finishSpan) expect: scopeManager.active() == childScope - childScope.span().context().parentId == parentScope.span().context().spanId - childScope.span().context().trace == parentScope.span().context().trace + noopChild || childScope.span().context().parentId == parentScope.span().context().spanId + noopChild || childScope.span().context().trace == parentScope.span().context().trace when: childScope.close() then: scopeManager.active() == parentScope - spanFinished(childScope.span()) == finishSpan + noopChild || spanFinished(childScope.span()) == finishSpan !spanFinished(parentScope.span()) writer == [] @@ -116,13 +116,17 @@ class ScopeManagerTest extends Specification { parentScope.close() then: - spanFinished(childScope.span()) == finishSpan + noopChild || spanFinished(childScope.span()) == finishSpan spanFinished(parentScope.span()) == finishSpan - writer == [[parentScope.span(), childScope.span()]] || !finishSpan + writer == [[parentScope.span(), childScope.span()]] || !finishSpan || noopChild scopeManager.active() == null where: - finishSpan << [true, false] + finishSpan | noopChild + true | false + false | false + true | true + false | true } def "ContinuableScope only creates continuations when propagation is set"() { @@ -568,7 +572,7 @@ class ScopeManagerTest extends Specification { } boolean spanFinished(Span span) { - return ((DDSpan) span).isFinished() + return ((DDSpan) span)?.isFinished() } class AtomicReferenceScope extends AtomicReference implements ScopeContext, Scope { diff --git a/settings.gradle b/settings.gradle index dcd99258c7..9b53bf92ac 100644 --- a/settings.gradle +++ b/settings.gradle @@ -41,6 +41,7 @@ include ':dd-java-agent:instrumentation:elasticsearch:transport-5' include ':dd-java-agent:instrumentation:elasticsearch:transport-5.3' include ':dd-java-agent:instrumentation:elasticsearch:transport-6' include ':dd-java-agent:instrumentation:glassfish' +include ':dd-java-agent:instrumentation:google-http-client' include ':dd-java-agent:instrumentation:grpc-1.5' include ':dd-java-agent:instrumentation:hibernate' include ':dd-java-agent:instrumentation:hibernate:core-3.3'