diff --git a/dd-java-agent-ittests/pom.xml b/dd-java-agent-ittests/pom.xml index ab40e0100a0..bb97ac7da68 100644 --- a/dd-java-agent-ittests/pom.xml +++ b/dd-java-agent-ittests/pom.xml @@ -169,6 +169,28 @@ test + + + + javax.jms + javax.jms-api + 2.0.1 + test + + + org.apache.activemq.tooling + activemq-junit + 5.14.5 + test + + + org.apache.activemq + activemq-broker + 5.14.5 + test + + + diff --git a/dd-java-agent-ittests/src/test/java/com/datadoghq/trace/instrument/JMSInstrumentationTest.java b/dd-java-agent-ittests/src/test/java/com/datadoghq/trace/instrument/JMSInstrumentationTest.java new file mode 100644 index 00000000000..56e685c0e5b --- /dev/null +++ b/dd-java-agent-ittests/src/test/java/com/datadoghq/trace/instrument/JMSInstrumentationTest.java @@ -0,0 +1,48 @@ +package com.datadoghq.trace.instrument; + +import io.opentracing.contrib.jms.TracingMessageProducer; +import io.opentracing.contrib.jms.common.TracingMessageConsumer; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.junit.EmbeddedActiveMQBroker; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import javax.jms.*; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JMSInstrumentationTest { + + + @ClassRule + public static EmbeddedActiveMQBroker broker = new EmbeddedActiveMQBroker(); + private static Session session; + private static ActiveMQQueue destination; + + @BeforeClass + public static void start() throws JMSException { + + broker.start(); + ActiveMQConnectionFactory connectionFactory = broker.createConnectionFactory(); + + destination = new ActiveMQQueue("someQueue"); + Connection connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + } + + @Test + public void test() throws Exception { + + + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + + assertThat(producer).isInstanceOf(TracingMessageProducer.class); + assertThat(consumer).isInstanceOf(TracingMessageConsumer.class); + } + +} diff --git a/dd-java-agent/pom.xml b/dd-java-agent/pom.xml index d8f8236497e..6defb66d7eb 100644 --- a/dd-java-agent/pom.xml +++ b/dd-java-agent/pom.xml @@ -27,6 +27,7 @@ 0.0.2 0.0.2 0.0.2 + 0.0.3 1.7 @@ -139,6 +140,25 @@ provided + + + io.opentracing.contrib + opentracing-jms-2 + ${ot.contrib.jms.version} + + + javax.jms + javax.jms-api + + + + + javax.jms + javax.jms-api + 2.0.1 + provided + + io.opentracing.contrib @@ -216,6 +236,32 @@ + + + io.opentracing + opentracing-mock + ${opentracing.version} + test + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.6.2 + test + + + org.mockito + mockito-core + 2.7.22 + test + + ${project.artifactId} diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/InstrumentationChecker.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/InstrumentationChecker.java new file mode 100644 index 00000000000..be20cbcad45 --- /dev/null +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/InstrumentationChecker.java @@ -0,0 +1,137 @@ +package io.opentracing.contrib.agent; + +import com.datadoghq.trace.resolver.FactoryUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * Utility class to check the validity of the classpath concerning the java automated instrumentations + */ +public class InstrumentationChecker { + + private static final String CONFIG_FILE = "dd-trace-supported-framework.yaml"; + private final Map>> rules; + private final Map frameworks; + + private static InstrumentationChecker INSTANCE; + + /* For testing purpose */ + InstrumentationChecker(Map>> rules, Map frameworks) { + this.rules = rules; + this.frameworks = frameworks; + INSTANCE = this; + } + + private InstrumentationChecker() { + rules = FactoryUtils.loadConfigFromResource(CONFIG_FILE, Map.class); + frameworks = scanLoadedLibraries(); + + } + + /** + * Return a list of unsupported rules regarding loading deps + * + * @return the list of unsupported rules + */ + public synchronized static List getUnsupportedRules() { + + if (INSTANCE == null) { + INSTANCE = new InstrumentationChecker(); + } + + return INSTANCE.doGetUnsupportedRules(); + } + + private List doGetUnsupportedRules() { + + List unsupportedRules = new ArrayList<>(); + for (String rule : rules.keySet()) { + + // Check rules + boolean supported = false; + for (Map check : rules.get(rule)) { + if (frameworks.containsKey(check.get("artifact"))) { + boolean matched = Pattern.matches(check.get("supported_version"), frameworks.get(check.get("artifact"))); + if (!matched) { + supported = false; + break; + } + supported = true; + } + } + + if (!supported) { + unsupportedRules.add(rule); + } + } + + return unsupportedRules; + + } + + + private static Map scanLoadedLibraries() { + + Map frameworks = new HashMap<>(); + + // Scan classpath provided jars + List jars = getJarFiles(System.getProperty("java.class.path")); + for (File file : jars) { + + String jarName = file.getName(); + String version = extractJarVersion(jarName); + + if (version != null) { + + // Extract artifactId + String artifactId = file.getName().substring(0, jarName.indexOf(version) - 1); + + // Store it + frameworks.put(artifactId, version); + } + } + + return frameworks; + } + + + private static List getJarFiles(String paths) { + List filesList = new ArrayList(); + for (final String path : paths.split(File.pathSeparator)) { + final File file = new File(path); + if (file.isDirectory()) { + recurse(filesList, file); + } else { + if (file.getName().endsWith(".jar")) { + filesList.add(file); + } + } + } + return filesList; + } + + private static void recurse(List filesList, File f) { + File list[] = f.listFiles(); + for (File file : list) { + getJarFiles(file.getPath()); + } + } + + private static String extractJarVersion(String jarName) { + + Pattern versionPattern = Pattern.compile("-(\\d+\\..+)\\.jar"); + Matcher matcher = versionPattern.matcher(jarName); + if (matcher.find()) { + return matcher.group(1); + } else { + return null; + } + } +} \ No newline at end of file diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/JarVersionsChecker.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/JarVersionsChecker.java deleted file mode 100644 index 959a0b06ed3..00000000000 --- a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/JarVersionsChecker.java +++ /dev/null @@ -1,119 +0,0 @@ -package io.opentracing.contrib.agent; - -import com.datadoghq.trace.resolver.FactoryUtils; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -/** - * Utility class to check the validity of the classpath concerning the java automated instrumentations - */ -public class JarVersionsChecker { - - private static Logger log = Logger.getLogger(JarVersionsChecker.class.getName()); - - public static String AUTHORIZED_VERSIONS_CONFIG = "dd-trace-authorized-versions.yaml"; - - /** - * Retrieves all the jars from the classpath - */ - private static List getJarsFromClasspath() { - return JarVersionsChecker.getJarFiles(System.getProperty("java.class.path")); - } - - /** - * list files in the given directory and subdirs (with recursion) - * - * @param paths - * @return - */ - public static List getJarFiles(String paths) { - List filesList = new ArrayList(); - for (final String path : paths.split(File.pathSeparator)) { - final File file = new File(path); - if (file.isDirectory()) { - recurse(filesList, file); - } else { - if (file.getName().endsWith(".jar")) { - filesList.add(file); - } - } - } - return filesList; - } - - private static void recurse(List filesList, File f) { - File list[] = f.listFiles(); - for (File file : list) { - getJarFiles(file.getPath()); - } - } - - public static Pattern versionPattern = Pattern.compile("-(\\d+\\..+)\\.jar"); - - public static String extractJarVersion(String jarName) { - Matcher matcher = versionPattern.matcher(jarName); - if (matcher.find()) - return matcher.group(1); - else - return null; - - } - - - public static void main(String args[]) throws Exception { - checkJarVersions(); - } - - /** - * Check all Jar versions in the classpath - * - * @return the list of jar keys that have been detected as potential issues - */ - @SuppressWarnings("unchecked") - public static List checkJarVersions() { - List potentialIssues = new ArrayList<>(); - - //Load instrumentations versions - Map> versions = FactoryUtils.loadConfigFromResource(AUTHORIZED_VERSIONS_CONFIG, Map.class); - if (versions == null) { - log.log(Level.WARNING, "DD agent: Authorized versions configuration file {} not found in classpath. Cannot proceed to the Jar versions check.", AUTHORIZED_VERSIONS_CONFIG); - return potentialIssues; - } - - //Scan classpath provided jars - List jars = getJarsFromClasspath(); - for (File file : jars) { - String jarName = file.getName(); - String versionRestrictions = extractJarVersion(jarName); - - if (versionRestrictions != null) { - //Extract artifactId - String artifactId = file.getName().substring(0, jarName.indexOf(versionRestrictions) - 1); - Map restrictions = versions.get(artifactId); - if (restrictions != null) { - String versionPattern = restrictions.get("valid_versions"); - if (versionPattern != null) { - if (!Pattern.matches(versionPattern, versionRestrictions)) { - String key = restrictions.get("key"); - if (key != null) { - potentialIssues.add(key); - } - log.log(Level.WARNING, "DD agent: The JAR {0} has been found in the classpath. It may create some intrumentation issue, some rules are about to get disabled.", jarName); - } - } - } - } - } - return potentialIssues; - } - - -} \ No newline at end of file diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java index 9ba98ab60e4..06da8e3ad44 100644 --- a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java @@ -56,7 +56,7 @@ public static void initialize(Retransformer trans) throws Exception { List loadedScripts = loadRules(ClassLoader.getSystemClassLoader()); //Check if some rules have to be uninstalled - List uninstallScripts = new ArrayList<>(); + List uninstallScripts = InstrumentationChecker.getUnsupportedRules(); if(agentTracerConfig != null){ List disabledInstrumentations = agentTracerConfig.getDisabledInstrumentations(); if(disabledInstrumentations!=null && !disabledInstrumentations.isEmpty()){ diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/DDAgentTracingHelper.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/DDAgentTracingHelper.java index dd67f43b50d..f888dad53a4 100644 --- a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/DDAgentTracingHelper.java +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/DDAgentTracingHelper.java @@ -11,9 +11,9 @@ /** * This class provides helpfull stuff in order to easy patch object using Byteman rules * - * @param The type of the object to patch + * @param The type of the object to patch */ -public abstract class DDAgentTracingHelper extends OpenTracingHelper { +public abstract class DDAgentTracingHelper extends OpenTracingHelper { private static final Logger LOGGER = Logger.getLogger(DDAgentTracingHelper.class.getCanonicalName()); @@ -48,15 +48,22 @@ public abstract class DDAgentTracingHelper extends OpenTracingHelper * @param args The object to patch, the type is defined by the subclass instantiation * @return The object patched */ - public ObjectType patch(ObjectType args) { + public T patch(T args) { - info("Try to patch " + args.getClass().getName()); - ObjectType patched; + if (args == null) { + info("Skipping " + rule.getName() + "' rule because the input arg is null"); + return args; + } + + String className = args.getClass().getName(); + info("Try to patch " + className); + + T patched; try { patched = doPatch(args); - info(args.getClass().getName() + " patched"); + info(className + " patched"); } catch (Throwable e) { - warning("Failed to patch" + args.getClass().getName() + ", reason: " + e.getMessage()); + warning("Failed to patch" + className + ", reason: " + e.getMessage()); logStackTrace(e.getMessage(), e); patched = args; } @@ -70,7 +77,7 @@ public ObjectType patch(ObjectType args) { * @return the object patched * @throws Exception The exceptions are managed directly to the patch method */ - abstract protected ObjectType doPatch(ObjectType obj) throws Exception; + abstract protected T doPatch(T obj) throws Exception; /** diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageConsumerHelper.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageConsumerHelper.java new file mode 100644 index 00000000000..3f674f6c051 --- /dev/null +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageConsumerHelper.java @@ -0,0 +1,34 @@ +package io.opentracing.contrib.agent.helper; + +import io.opentracing.contrib.jms.common.TracingMessageConsumer; +import org.jboss.byteman.rule.Rule; + +import javax.jms.MessageConsumer; + +public class JMSMessageConsumerHelper extends DDAgentTracingHelper { + + public JMSMessageConsumerHelper(Rule rule) { + super(rule); + } + + + @Override + public MessageConsumer patch(MessageConsumer args) { + return super.patch(args); + } + + /** + * Strategy: Wrapper the instance into a new one. + * + * @param consumer The JMS instance + * @return A new instance with the old one wrapped + * @throws Exception + */ + protected MessageConsumer doPatch(MessageConsumer consumer) throws Exception { + if (consumer instanceof TracingMessageConsumer) { + return consumer; + } + return new TracingMessageConsumer(consumer, tracer); + } + +} \ No newline at end of file diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageProducerHelper.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageProducerHelper.java new file mode 100644 index 00000000000..fee56b6bb29 --- /dev/null +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/JMSMessageProducerHelper.java @@ -0,0 +1,32 @@ +package io.opentracing.contrib.agent.helper; + +import io.opentracing.contrib.jms.TracingMessageProducer; +import org.jboss.byteman.rule.Rule; + +import javax.jms.MessageProducer; + +public class JMSMessageProducerHelper extends DDAgentTracingHelper { + + public JMSMessageProducerHelper(Rule rule) { + super(rule); + } + + @Override + public MessageProducer patch(MessageProducer args) { + return super.patch(args); + } + + /** + * Strategy: Wrapper the instance into a new one. + * + * @param producer The JMS instance + * @return A new instance with the old one wrapped + * @throws Exception + */ + protected MessageProducer doPatch(MessageProducer producer) throws Exception { + if (producer instanceof TracingMessageProducer) { + return producer; + } + return new TracingMessageProducer(producer, tracer); + } +} \ No newline at end of file diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java index de1531fe091..4497a8171c1 100644 --- a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java @@ -28,6 +28,8 @@ protected MongoClientOptions.Builder doPatch(MongoClientOptions.Builder builder) TracingCommandListener listener = new TracingCommandListener(tracer); builder.addCommandListener(listener); + setState(builder, 1); + return builder; } diff --git a/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml b/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml new file mode 100644 index 00000000000..170f2b13597 --- /dev/null +++ b/dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml @@ -0,0 +1,61 @@ +### This file define all supported libraries +### Syntax: +### : # the rule name defined in the otarules.btm +### - check: # a list of tests, if one not matched, thus the rule is removed +### articfact: # the artifact name to be tested +### supported_version: # a regex expression to express the version required by the rule +### - check: ... + +opentracing-apache-httpclient: + - check: + artifact: httpclient + supported_version: 4\.[3|4|5]\..* + - check: + artifact: commons-httpclient + supported_version: none + +opentracing-aws-sdk: + - check: + artifact: aws-java-sdk + supported_version: 1\.11\..* + +opentracing-elasticsearch-client: + - check: + artifact: transport + supported_version: 5\.4\..* + +opentracing-cassandra-driver: + - check: + artifact: cassandra-driver-core + supported_version: 3\.2.* + +opentracing-web-servlet-filter: + - check: + artifact: jetty-server + supported_version: (8\.|9\.).* + - check: + artifact: tomcat_catalina + supported_version: (8\.|9\.).* + - check: + artifact: tomcat-embed-core + supported_version: (8\.|9\.).* + +opentracing-okhttp3: + - check: + artifact: okhttp + supported_version: 3\..* + +# For rules opentracing-jms-2_{consumer,producer} +opentracing-jms-2: + - check: + artifact: jms-api + supported_version: 2\..* + +opentracing-mongo-driver: + - check: + artifact: mongo-java-driver + supported_version: 3\..* + - check: + artifact: mongodb-driver-async + supported_version: 3\..* + diff --git a/dd-java-agent/src/main/resources/otarules.btm b/dd-java-agent/src/main/resources/otarules.btm index 1eae62a3af6..981d83efe61 100644 --- a/dd-java-agent/src/main/resources/otarules.btm +++ b/dd-java-agent/src/main/resources/otarules.btm @@ -1,11 +1,21 @@ +### The contributions are injected using this file and byteman +### +### Helpers are a DD specific, they are defined in the current project +### The rule names provided (RULE ) are also used in the configuration. +### The name is used to remove the script if there is no support of the framework +### +### So, ensure that the rule name is correct defined both here and in the dd-trace-supported-framework.yaml +### + + # Instrument Mongo client # ======================== -RULE mongo +RULE opentracing-mongo-driver CLASS com.mongodb.MongoClientOptions$Builder METHOD build HELPER io.opentracing.contrib.agent.helper.MongoHelper AT ENTRY -IF TRUE +IF getState($0) == 0 DO patch($this); ENDRULE @@ -13,7 +23,7 @@ ENDRULE # Instrument AWS SDK client # ========================== -RULE awsclient +RULE opentracing-aws-sdk CLASS ^com.amazonaws.client.builder.AwsClientBuilder METHOD build() HELPER io.opentracing.contrib.agent.helper.AWSClientHelper @@ -23,9 +33,10 @@ DO patch($this); ENDRULE + # Instrument Apache HTTP Client # ============================= -RULE apache http +RULE opentracing-apache-httpclient CLASS org.apache.http.impl.client.HttpClientBuilder METHOD create() HELPER io.opentracing.contrib.agent.helper.ApacheHTTPClientHelper @@ -35,9 +46,10 @@ DO $! = patch($!); ENDRULE + # Instrument Elasticsearch Transport Client # ========================================== -RULE elasticsearch +RULE opentracing-elasticsearch-client INTERFACE org.elasticsearch.client.ElasticsearchClient METHOD execute(org.elasticsearch.action.Action,org.elasticsearch.action.ActionRequest,org.elasticsearch.action.ActionListener) HELPER io.opentracing.contrib.agent.helper.ElasticsearchHelper @@ -48,9 +60,10 @@ DO $3 = patch($3); ENDRULE + # Instrument Cassandra client # =========================== -RULE cassandra +RULE opentracing-cassandra-driver CLASS com.datastax.driver.core.Cluster$Manager METHOD newSession() HELPER io.opentracing.contrib.agent.helper.CassandraHelper @@ -61,12 +74,11 @@ DO ENDRULE - # Instrument Jetty # =========================== # State 0 - no filter installed # State 1 - filter installed -RULE jetty +RULE opentracing-web-servlet-filter_jetty CLASS org.eclipse.jetty.servlet.ServletContextHandler METHOD HELPER io.opentracing.contrib.agent.helper.JettyServletHelper @@ -79,7 +91,7 @@ ENDRULE # Instrument Tomcat # =========================== -RULE tomcat +RULE opentracing-web-servlet-filter_tomcat CLASS org.apache.catalina.core.ApplicationContext METHOD HELPER io.opentracing.contrib.agent.helper.TomcatServletHelper @@ -90,10 +102,9 @@ DO ENDRULE - # Instrument OkHttp # =========================== -RULE okhttp +RULE opentracing-okhttp3 CLASS okhttp3.OkHttpClient$Builder METHOD build() HELPER io.opentracing.contrib.agent.helper.OkHttpHelper @@ -102,3 +113,28 @@ IF TRUE DO patch($this) ENDRULE + + +# Instrument JMS +# =========================== +RULE opentracing-jms-2_producer +INTERFACE javax.jms.Session +METHOD createProducer +HELPER io.opentracing.contrib.agent.helper.JMSMessageProducerHelper +AT EXIT +IF TRUE +DO + $! = patch($!); +ENDRULE + + +RULE opentracing-jms-2_consumer +INTERFACE javax.jms.Session +METHOD createConsumer +HELPER io.opentracing.contrib.agent.helper.JMSMessageConsumerHelper +AT EXIT +IF TRUE +DO + $! = patch($!); +ENDRULE + diff --git a/dd-java-agent/src/test/java/io/opentracing/contrib/agent/InstrumentationCheckerTest.java b/dd-java-agent/src/test/java/io/opentracing/contrib/agent/InstrumentationCheckerTest.java new file mode 100644 index 00000000000..1f84e5b8bc1 --- /dev/null +++ b/dd-java-agent/src/test/java/io/opentracing/contrib/agent/InstrumentationCheckerTest.java @@ -0,0 +1,40 @@ +package io.opentracing.contrib.agent; + +import com.datadoghq.trace.resolver.FactoryUtils; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class InstrumentationCheckerTest { + + + @Before + public void setup() { + Map>> rules = FactoryUtils.loadConfigFromResource("supported-version-test.yaml", Map.class); + Map frameworks = new HashMap() {{ + put("artifact-1", "1.2.3.1232"); + put("artifact-2", "4.y.z"); + put("artifact-3", "5.123-1"); + }}; + + new InstrumentationChecker(rules, frameworks); + } + + + @Test + public void testRules() throws Exception { + + + List rules = InstrumentationChecker.getUnsupportedRules(); + assertThat(rules.size()).isEqualTo(3); + assertThat(rules).containsExactlyInAnyOrder("unsupportedRuleOne", "unsupportedRuleTwo", "unsupportedRuleThree"); + + + } + +} \ No newline at end of file diff --git a/dd-java-agent/src/test/resources/supported-version-test.yaml b/dd-java-agent/src/test/resources/supported-version-test.yaml new file mode 100644 index 00000000000..d19e82a4153 --- /dev/null +++ b/dd-java-agent/src/test/resources/supported-version-test.yaml @@ -0,0 +1,26 @@ +unsupportedRuleOne: + - check: + artifact: artifact-1 + supported_version: 1\.2\.3\..* + - check: + artifact: artifact-2 + supported_version: none +unsupportedRuleTwo: + - check: + artifact: artifact-1 + supported_version: 2\.3\. +supportedRuleOne: + - check: + artifact: artifact-3 + supported_version: 5\..* +supportedRuleTwo: + - check: + artifact: artifact-1 + supported_version: 1\.2\.3\..* + - check: + artifact: artifact-2 + supported_version: 4\..* +unsupportedRuleThree: + - check: + artifact: foo + supported_version: 1 diff --git a/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml b/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml index bc6406af2f0..beb8b2b734f 100644 --- a/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml +++ b/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml @@ -12,7 +12,7 @@ writer: host: localhost port: 8126 -# The sampler to use. +# The sampling to use. # Could be: AllSampler (default) or RateSampler sampler: # AllSampler: all spans are reported to the writer diff --git a/dd-trace/pom.xml b/dd-trace/pom.xml index d518f6c784e..38dc586304d 100644 --- a/dd-trace/pom.xml +++ b/dd-trace/pom.xml @@ -14,10 +14,6 @@ Datadog core library https://github.com/datadog/dd-trace-java - - 1.6 - - diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java b/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java index dbe5307f9a7..dd6bde94f2f 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java @@ -3,6 +3,7 @@ import com.datadoghq.trace.integration.DDSpanContextDecorator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.collect.Maps; import io.opentracing.tag.Tags; import java.util.*; @@ -21,6 +22,8 @@ public class DDSpanContext implements io.opentracing.SpanContext { private final long traceId; private final long spanId; private final long parentId; + private final String threadName = Thread.currentThread().getName(); + private final long threadId = Thread.currentThread().getId(); private Map baggageItems; // DD attributes @@ -126,7 +129,7 @@ public String getResourceName() { public boolean getErrorFlag() { return errorFlag; } - + public void setErrorFlag(boolean errorFlag) { this.errorFlag = errorFlag; } @@ -193,6 +196,11 @@ public synchronized void setTag(String tag, Object value) { } public synchronized Map getTags() { + if(tags.isEmpty()) { + tags = Maps.newHashMapWithExpectedSize(2); + } + tags.put(DDTags.THREAD_NAME, threadName); + tags.put(DDTags.THREAD_ID, threadId); return Collections.unmodifiableMap(tags); } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDTags.java b/dd-trace/src/main/java/com/datadoghq/trace/DDTags.java index 5b49c4dd566..1b8920c4fb7 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/DDTags.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDTags.java @@ -4,4 +4,6 @@ public class DDTags { public static final String SPAN_TYPE = "span-type"; public static final String SERVICE_NAME = "service-name"; public static final String RESOURCE_NAME = "resource-name"; + public static final String THREAD_NAME = "thread-name"; + public static final String THREAD_ID = "thread-id"; } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/propagation/HTTPCodec.java b/dd-trace/src/main/java/com/datadoghq/trace/propagation/HTTPCodec.java index e440ef9c5be..c3d6e12a2d7 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/propagation/HTTPCodec.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/propagation/HTTPCodec.java @@ -1,7 +1,6 @@ package com.datadoghq.trace.propagation; import com.datadoghq.trace.DDSpanContext; - import io.opentracing.propagation.TextMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,86 +17,86 @@ */ public class HTTPCodec implements Codec { - private static final String OT_PREFIX = "ot-tracer-"; - private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"; - private static final String TRACE_ID_KEY = OT_PREFIX + "traceid"; - private static final String SPAN_ID_KEY = OT_PREFIX + "spanid"; - - private static final Logger logger = LoggerFactory.getLogger(HTTPCodec.class); - - @Override - public void inject(DDSpanContext context, TextMap carrier) { - - carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId())); - carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId())); - - for (Map.Entry entry : context.baggageItems()) { - carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue())); - } - } - - @Override - public DDSpanContext extract(TextMap carrier) { - - Map baggage = Collections.emptyMap(); - Long traceId = 0L; - Long spanId = 0L; - - for (Map.Entry entry : carrier) { - - if (entry.getKey().equals(TRACE_ID_KEY)) { - traceId = Long.parseLong(entry.getValue()); - } else if (entry.getKey().equals(SPAN_ID_KEY)) { - spanId = Long.parseLong(entry.getValue()); - } else if (entry.getKey().startsWith(OT_BAGGAGE_PREFIX)) { - if (baggage.isEmpty()) { - baggage = new HashMap(); - } - baggage.put(entry.getKey(), decode(entry.getValue())); - } - } - DDSpanContext context = null; - if (traceId != 0L) { - - context = new DDSpanContext( - traceId, - spanId, - 0L, - null, - null, - null, - baggage, - false, - null, - null, - null, - null); - - logger.debug("{} - Parent context extracted", context); - } - - return context; - } - - - private String encode(String value) { - String encoded = value; - try { - encoded = URLEncoder.encode(value, "UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.info("Failed to encode value - {}", value); - } - return encoded; - } - - private String decode(String value) { - String decoded = value; - try { - decoded = URLDecoder.decode(value, "UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.info("Failed to decode value - {}", value); - } - return decoded; - } + private static final String OT_PREFIX = "ot-tracer-"; + private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"; + private static final String TRACE_ID_KEY = OT_PREFIX + "traceid"; + private static final String SPAN_ID_KEY = OT_PREFIX + "spanid"; + + private static final Logger logger = LoggerFactory.getLogger(HTTPCodec.class); + + @Override + public void inject(DDSpanContext context, TextMap carrier) { + + carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId())); + carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId())); + + for (Map.Entry entry : context.baggageItems()) { + carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue())); + } + } + + @Override + public DDSpanContext extract(TextMap carrier) { + + Map baggage = Collections.emptyMap(); + Long traceId = 0L; + Long spanId = 0L; + + for (Map.Entry entry : carrier) { + + if (entry.getKey().equals(TRACE_ID_KEY)) { + traceId = Long.parseLong(entry.getValue()); + } else if (entry.getKey().equals(SPAN_ID_KEY)) { + spanId = Long.parseLong(entry.getValue()); + } else if (entry.getKey().startsWith(OT_BAGGAGE_PREFIX)) { + if (baggage.isEmpty()) { + baggage = new HashMap(); + } + baggage.put(entry.getKey().replace(OT_BAGGAGE_PREFIX, ""), decode(entry.getValue())); + } + } + DDSpanContext context = null; + if (traceId != 0L) { + + context = new DDSpanContext( + traceId, + spanId, + 0L, + null, + null, + null, + baggage, + false, + null, + null, + null, + null); + + logger.debug("{} - Parent context extracted", context); + } + + return context; + } + + + private String encode(String value) { + String encoded = value; + try { + encoded = URLEncoder.encode(value, "UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.info("Failed to encode value - {}", value); + } + return encoded; + } + + private String decode(String value) { + String decoded = value; + try { + decoded = URLDecoder.decode(value, "UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.info("Failed to decode value - {}", value); + } + return decoded; + } } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/resolver/DDTracerFactory.java b/dd-trace/src/main/java/com/datadoghq/trace/resolver/DDTracerFactory.java index 59a9ee8fbaa..1680167661f 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/resolver/DDTracerFactory.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/resolver/DDTracerFactory.java @@ -1,7 +1,7 @@ package com.datadoghq.trace.resolver; import com.datadoghq.trace.DDTracer; -import com.datadoghq.trace.sampling.ASampler; +import com.datadoghq.trace.sampling.AbstractSampler; import com.datadoghq.trace.sampling.AllSampler; import com.datadoghq.trace.sampling.RateSampler; import com.datadoghq.trace.sampling.Sampler; @@ -74,8 +74,8 @@ public static DDTracer create(TracerConfig config) { //Add sampled tags Map skipTagsPatterns = config.getSampler().getSkipTagsPatterns(); - if (skipTagsPatterns != null && sampler instanceof ASampler) { - ASampler aSampler = (ASampler) sampler; + if (skipTagsPatterns != null && sampler instanceof AbstractSampler) { + AbstractSampler aSampler = (AbstractSampler) sampler; for (Map.Entry entry : skipTagsPatterns.entrySet()) { aSampler.addSkipTagPattern(entry.getKey(), Pattern.compile(entry.getValue())); } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AbstractSampler.java similarity index 94% rename from dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java rename to dd-trace/src/main/java/com/datadoghq/trace/sampling/AbstractSampler.java index 38d00be2b08..442d156521e 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AbstractSampler.java @@ -1,13 +1,13 @@ package com.datadoghq.trace.sampling; +import com.datadoghq.trace.DDBaseSpan; + import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; -import com.datadoghq.trace.DDBaseSpan; - -public abstract class ASampler implements Sampler{ +public abstract class AbstractSampler implements Sampler { /** * Sample tags diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java index 25bd06e8fe0..ec195d9d784 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java @@ -5,7 +5,7 @@ /** * Sampler that always says yes... */ -public class AllSampler extends ASampler { +public class AllSampler extends AbstractSampler { @Override public boolean doSample(DDBaseSpan span) { diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java index 48b718299ea..dd33797f61e 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java @@ -1,11 +1,10 @@ package com.datadoghq.trace.sampling; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.datadoghq.trace.DDBaseSpan; import com.google.auto.service.AutoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** @@ -15,7 +14,7 @@ * It samples randomly, its main purpose is to reduce the instrumentation footprint. */ @AutoService(Sampler.class) -public class RateSampler extends ASampler { +public class RateSampler extends AbstractSampler { private final static Logger logger = LoggerFactory.getLogger(RateSampler.class); diff --git a/dd-trace/src/test/java/ExampleWithDDAgentWriter.java b/dd-trace/src/test/java/ExampleWithDDAgentWriter.java deleted file mode 100644 index 70eeb9e911c..00000000000 --- a/dd-trace/src/test/java/ExampleWithDDAgentWriter.java +++ /dev/null @@ -1,54 +0,0 @@ -import com.datadoghq.trace.DDTracer; -import com.datadoghq.trace.sampling.AllSampler; -import com.datadoghq.trace.sampling.Sampler; -import com.datadoghq.trace.writer.DDAgentWriter; -import com.datadoghq.trace.writer.Writer; - -import io.opentracing.Span; - -public class ExampleWithDDAgentWriter { - - public static void main(String[] args) throws Exception { - - // Instantiate the DDWriter - // By default, traces are written to localhost:8126 (the ddagent) - Writer writer = new DDAgentWriter(); - - // Instantiate the proper Sampler - // - RateSampler if you want to keep `ratio` traces - // - AllSampler to keep all traces - Sampler sampler = new AllSampler(); - - - // Create the tracer - DDTracer tracer = new DDTracer(writer, sampler); - - - Span parent = tracer - .buildSpan("hello-world") - .withServiceName("service-name") - .withSpanType("web") - .start(); - - Thread.sleep(100); - - parent.setBaggageItem("a-baggage", "value"); - - Span child = tracer - .buildSpan("hello-world") - .asChildOf(parent) - .withResourceName("resource-name") - .start(); - - Thread.sleep(100); - - child.finish(); - - Thread.sleep(100); - - parent.finish(); - - writer.close(); - - } -} \ No newline at end of file diff --git a/dd-trace/src/test/java/com/datadoghq/trace/AllSamplerTest.java b/dd-trace/src/test/java/com/datadoghq/trace/AllSamplerTest.java deleted file mode 100644 index de9268cc30a..00000000000 --- a/dd-trace/src/test/java/com/datadoghq/trace/AllSamplerTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.datadoghq.trace; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -import org.junit.Test; - -import com.datadoghq.trace.sampling.AllSampler; - -public class AllSamplerTest { - - - @Test - public void testAllSampler() { - - - - AllSampler sampler = new AllSampler(); - sampler.addSkipTagPattern("http.url", Pattern.compile(".*/hello")); - - DDSpan mockSpan = mock(DDSpan.class); - Map tags = new HashMap(); - tags.put("http.url", "http://a/hello"); - when(mockSpan.getTags()).thenReturn(tags).thenReturn(tags); - - assertThat(sampler.sample(mockSpan)).isEqualTo(false); - - tags.put("http.url", "http://a/hello2"); - - assertThat(sampler.sample(mockSpan)).isEqualTo(true); - - } -} \ No newline at end of file diff --git a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java index 642b16aad69..6e6d6dabd84 100644 --- a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java +++ b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java @@ -66,7 +66,7 @@ public void shouldBuildMoreComplexSpan() { .start(); assertThat(span.getTags()).isNotNull(); - assertThat(span.getTags()).isEmpty(); + assertThat(span.getTags().size()).isEqualTo(2); // with all custom fields provided final String expectedResource = "fakeResource"; @@ -88,7 +88,8 @@ public void shouldBuildMoreComplexSpan() { assertThat(actualContext.getErrorFlag()).isTrue(); assertThat(actualContext.getServiceName()).isEqualTo(expectedService); assertThat(actualContext.getSpanType()).isEqualTo(expectedType); - + assertThat(actualContext.getTags().get(DDTags.THREAD_NAME)).isEqualTo(Thread.currentThread().getName()); + assertThat(actualContext.getTags().get(DDTags.THREAD_ID)).isEqualTo(Thread.currentThread().getId()); } diff --git a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializationTest.java b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializationTest.java index ff7cbc5dc0f..cb55e784032 100644 --- a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializationTest.java +++ b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializationTest.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Map; +import com.google.common.collect.Maps; import org.junit.Before; import org.junit.Test; @@ -16,15 +17,28 @@ public class DDSpanSerializationTest { ObjectMapper serializer; DDSpan span; DDActiveSpan activeSpan; + Map expected = Maps.newHashMap(); @Before public void setUp() throws Exception { - Map baggage = new HashMap(); + Map baggage = new HashMap<>(); baggage.put("a-baggage", "value"); - Map tags = new HashMap(); + Map tags = new HashMap<>(); baggage.put("k1", "v1"); + expected.put("meta", baggage); + expected.put("service", "service"); + expected.put("error", 0); + expected.put("type", "type"); + expected.put("name", "operation"); + expected.put("duration", 33000); + expected.put("resource", "operation"); + expected.put("start", 100000); + expected.put("span_id", 2l); + expected.put("parent_id", 0l); + expected.put("trace_id", 1l); + DDSpanContext context = new DDSpanContext( 1L, @@ -33,13 +47,16 @@ public void setUp() throws Exception { "service", "operation", null, - baggage, + new HashMap(baggage), false, "type", tags, null, null); + baggage.put("thread-name", Thread.currentThread().getName()); + baggage.put("thread-id", String.valueOf(Thread.currentThread().getId())); + span = new DDSpan( 100L, context); @@ -52,22 +69,7 @@ public void setUp() throws Exception { @Test public void test() throws Exception { - - - String expected = "{\"meta\":{\"a-baggage\":\"value\",\"k1\":\"v1\"},\"service\":\"service\",\"error\":0,\"type\":\"type\",\"name\":\"operation\",\"duration\":33000,\"resource\":\"operation\",\"start\":100000,\"span_id\":2,\"parent_id\":0,\"trace_id\":1}"; - // FIXME At the moment, just compare the string sizes - try { - assertThat(serializer.writeValueAsString(span).length()).isEqualTo(expected.length()); - - } catch (AssertionError e) { - assertThat(serializer.writeValueAsString(span)).isEqualTo(expected); - } - -// try { -// assertThat(serializer.writeValueAsString(activeSpan).length()).isEqualTo(expected.length()); -// } catch (AssertionError e) { -// assertThat(serializer.writeValueAsString(activeSpan)).isEqualTo(expected); -// } + assertThat(serializer.readTree(serializer.writeValueAsString(span))) + .isEqualTo(serializer.readTree(serializer.writeValueAsString(expected))); } - } diff --git a/dd-trace/src/test/java/com/datadoghq/trace/propagation/HTTPCodecTest.java b/dd-trace/src/test/java/com/datadoghq/trace/propagation/HTTPCodecTest.java new file mode 100644 index 00000000000..1dd61d3d3e9 --- /dev/null +++ b/dd-trace/src/test/java/com/datadoghq/trace/propagation/HTTPCodecTest.java @@ -0,0 +1,84 @@ +package com.datadoghq.trace.propagation; + +import com.datadoghq.trace.DDSpanContext; +import io.opentracing.propagation.TextMapExtractAdapter; +import io.opentracing.propagation.TextMapInjectAdapter; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +/** + * Created by gpolaert on 6/23/17. + */ +public class HTTPCodecTest { + + + private static final String OT_PREFIX = "ot-tracer-"; + private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"; + private static final String TRACE_ID_KEY = OT_PREFIX + "traceid"; + private static final String SPAN_ID_KEY = OT_PREFIX + "spanid"; + + + @Test + public void shoudAddHttpHeaders() { + + DDSpanContext mockedContext = new DDSpanContext( + 1L, + 2L, + 0L, + "fakeService", + "fakeOperation", + "fakeResource", + new HashMap() {{ + put("k1", "v1"); + put("k2", "v2"); + }}, + false, + "fakeType", + null, + null, + null); + + Map carrier = new HashMap<>(); + + HTTPCodec codec = new HTTPCodec(); + codec.inject(mockedContext, new TextMapInjectAdapter(carrier)); + + + assertThat(carrier.get(TRACE_ID_KEY)).isEqualTo("1"); + assertThat(carrier.get(SPAN_ID_KEY)).isEqualTo("2"); + assertThat(carrier.get(OT_BAGGAGE_PREFIX + "k1")).isEqualTo("v1"); + assertThat(carrier.get(OT_BAGGAGE_PREFIX + "k2")).isEqualTo("v2"); + + + } + + + @Test + public void shoudReadHttpHeaders() { + + + Map actual = new HashMap() {{ + put(TRACE_ID_KEY, "1"); + put(SPAN_ID_KEY, "2"); + put(OT_BAGGAGE_PREFIX + "k1", "v1"); + put(OT_BAGGAGE_PREFIX + "k2", "v2"); + }}; + + + HTTPCodec codec = new HTTPCodec(); + DDSpanContext context = codec.extract(new TextMapExtractAdapter(actual)); + + assertThat(context.getTraceId()).isEqualTo(1l); + assertThat(context.getSpanId()).isEqualTo(2l); + assertThat(context.getBaggageItem("k1")).isEqualTo("v1"); + assertThat(context.getBaggageItem("k2")).isEqualTo("v2"); + + + } + + +} \ No newline at end of file diff --git a/dd-trace/src/test/java/com/datadoghq/trace/sampling/AllSamplerTest.java b/dd-trace/src/test/java/com/datadoghq/trace/sampling/AllSamplerTest.java new file mode 100644 index 00000000000..e0a6d7bed50 --- /dev/null +++ b/dd-trace/src/test/java/com/datadoghq/trace/sampling/AllSamplerTest.java @@ -0,0 +1,47 @@ +package com.datadoghq.trace.sampling; + +import com.datadoghq.trace.DDSpan; +import org.junit.Test; +import org.mockito.Mock; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AllSamplerTest { + + @Mock + DDSpan mockSpan; + + private final AllSampler sampler = new AllSampler(); + + + @Test + public void testAllSampler() { + + for (int i = 0; i < 500; i++) { + assertThat(sampler.doSample(mockSpan)).isTrue(); + } + } + + @Test + public void testSkipTagPatternSampler() { + + Map tags = new HashMap<>(); + mockSpan = mock(DDSpan.class); + when(mockSpan.getTags()).thenReturn(tags).thenReturn(tags); + + sampler.addSkipTagPattern("http.url", Pattern.compile(".*/hello")); + + tags.put("http.url", "http://a/hello"); + assertThat(sampler.sample(mockSpan)).isFalse(); + + tags.put("http.url", "http://a/hello2"); + assertThat(sampler.sample(mockSpan)).isTrue(); + + } +} \ No newline at end of file diff --git a/dd-trace/src/test/java/com/datadoghq/trace/sampling/ExampleWithDDAgentWriter.java b/dd-trace/src/test/java/com/datadoghq/trace/sampling/ExampleWithDDAgentWriter.java new file mode 100644 index 00000000000..b98ceb7c65d --- /dev/null +++ b/dd-trace/src/test/java/com/datadoghq/trace/sampling/ExampleWithDDAgentWriter.java @@ -0,0 +1,53 @@ +package com.datadoghq.trace.sampling; + +import com.datadoghq.trace.DDTracer; +import com.datadoghq.trace.writer.DDAgentWriter; +import com.datadoghq.trace.writer.Writer; +import io.opentracing.Span; + +public class ExampleWithDDAgentWriter { + + public static void main(String[] args) throws Exception { + + // Instantiate the DDWriter + // By default, traces are written to localhost:8126 (the ddagent) + Writer writer = new DDAgentWriter(); + + // Instantiate the proper Sampler + // - RateSampler if you want to keep `ratio` traces + // - AllSampler to keep all traces + Sampler sampler = new AllSampler(); + + + // Create the tracer + DDTracer tracer = new DDTracer(writer, sampler); + + + Span parent = tracer + .buildSpan("hello-world") + .withServiceName("service-name") + .withSpanType("web") + .start(); + + Thread.sleep(100); + + parent.setBaggageItem("a-baggage", "value"); + + Span child = tracer + .buildSpan("hello-world") + .asChildOf(parent) + .withResourceName("resource-name") + .start(); + + Thread.sleep(100); + + child.finish(); + + Thread.sleep(100); + + parent.finish(); + + writer.close(); + + } +} \ No newline at end of file