refactoring the version checker
MODIFY
dd-java-agent/pom.xml
dd-java-agent/pom.xml
</dependency>
<!-- JMS instrumentation -->
- <!--<dependency>-->
- <!--<groupId>io.opentracing.contrib</groupId>-->
- <!--<artifactId>opentracing-jms-1</artifactId>-->
- <!--<version>${ot.contrib.jms.version}</version>-->
- <!--<exclusions>-->
- <!--<exclusion>-->
- <!--<groupId>javax.jms</groupId>-->
- <!--<artifactId>jms-api</artifactId>-->
- <!--</exclusion>-->
- <!--</exclusions>-->
- <!--</dependency>-->
- <!--<dependency>-->
- <!--<groupId>javax.jms</groupId>-->
- <!--<artifactId>jms-api</artifactId>-->
- <!--<version>1.1-rev-1</version>-->
- <!--<scope>provided</scope>-->
- <!--</dependency>-->
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-jms-2</artifactId>
</dependency>
+ <!-- JUnit tests -->
+ <dependency>
+ <groupId>io.opentracing</groupId>
+ <artifactId>opentracing-mock</artifactId>
+ <version>${opentracing.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.6.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>2.7.22</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>

ADD
dd-java-agent/src/main/java/io/opentracing/contrib/agent/InstrumentationChecker.java
+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-framework-supported.yaml";
+ private final Map<String, List<Map<String, String>>> rules;
+ private final Map<String, String> frameworks;
+
+ private static InstrumentationChecker INSTANCE;
+
+ /* For testing purpose */
+ InstrumentationChecker(Map<String, List<Map<String, String>>> rules, Map<String, String> 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<String> getUnsupportedRules() {
+
+ if (INSTANCE == null) {
+ INSTANCE = new InstrumentationChecker();
+ }
+
+ return INSTANCE.doGetUnsupportedRules();
+ }
+
+ private List<String> doGetUnsupportedRules() {
+
+ List<String> unsupportedRules = new ArrayList<>();
+ for (String rule : rules.keySet()) {
+
+ // Check rules
+ boolean supported = false;
+ for (Map<String, String> 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<String, String> scanLoadedLibraries() {
+
+ Map<String, String> frameworks = new HashMap<>();
+
+ // Scan classpath provided jars
+ List<File> 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<File> getJarFiles(String paths) {
+ List<File> filesList = new ArrayList<File>();
+ 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<File> 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

DELETE
dd-java-agent/src/main/java/io/opentracing/contrib/agent/JarVersionsChecker.java
-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<File> 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<File> getJarFiles(String paths) {
- List<File> filesList = new ArrayList<File>();
- 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<File> 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<String> checkJarVersions() {
- List<String> potentialIssues = new ArrayList<>();
-
- //Load instrumentations versions
- Map<String, Map<String, String>> 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<File> 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<String, String> 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

MODIFY
dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java
dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java
@@ -56,7 +56,7 @@ public class TraceAnnotationsManager {
List<String> loadedScripts = loadRules(ClassLoader.getSystemClassLoader());
//Check if some rules have to be uninstalled
- List<String> uninstallScripts = new ArrayList<>();
+ List<String> uninstallScripts = InstrumentationChecker.getUnsupportedRules();
if(agentTracerConfig != null){
List<String> disabledInstrumentations = agentTracerConfig.getDisabledInstrumentations();
if(disabledInstrumentations!=null && !disabledInstrumentations.isEmpty()){

MODIFY
dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java
dd-java-agent/src/main/java/io/opentracing/contrib/agent/helper/MongoHelper.java
@@ -28,6 +28,8 @@ public class MongoHelper extends DDAgentTracingHelper<MongoClientOptions.Builder
TracingCommandListener listener = new TracingCommandListener(tracer);
builder.addCommandListener(listener);
+ setState(builder, 1);
+
return builder;
}

ADD
dd-java-agent/src/main/resources/dd-trace-framework-supported.yaml
+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\..*
+
+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\..*
+
+#todo jdbc, opentracing api
+
+#spring_jdbc:
+# artifact: jdbc
+# supported_version: 4\..*
+#hibernate-core:
+# artifact: jdbc
+# supported_version: 5\..*
+#opentracing-mongo-driver:
+# artifact: mongo-java-driver
+# supported_version: 3\..*
+#opentracing-api:
+# artifact: opentracing-api
+# supported_version: 0\.2.*
+

MODIFY
dd-java-agent/src/main/resources/otarules.btm
dd-java-agent/src/main/resources/otarules.btm
# 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 +13,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
@@ -25,7 +25,7 @@ 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
@@ -37,7 +37,7 @@ 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
@@ -50,7 +50,7 @@ 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
@@ -66,7 +66,7 @@ ENDRULE
# ===========================
# State 0 - no filter installed
# State 1 - filter installed
-RULE jetty
+RULE opentracing-web-servlet-filter_jetty
CLASS org.eclipse.jetty.servlet.ServletContextHandler
METHOD <init>
HELPER io.opentracing.contrib.agent.helper.JettyServletHelper
@@ -79,7 +79,7 @@ ENDRULE
# Instrument Tomcat
# ===========================
-RULE tomcat
+RULE opentracing-web-servlet-filter_tomcat
CLASS org.apache.catalina.core.ApplicationContext
METHOD <init>
HELPER io.opentracing.contrib.agent.helper.TomcatServletHelper
@@ -93,7 +93,7 @@ ENDRULE
# Instrument OkHttp
# ===========================
-RULE okhttp
+RULE opentracing-okhttp3
CLASS okhttp3.OkHttpClient$Builder
METHOD build()
HELPER io.opentracing.contrib.agent.helper.OkHttpHelper
@@ -106,7 +106,7 @@ ENDRULE
# Instrument JMS
# ===========================
-RULE jms producer
+RULE opentracing-jms-2_producer
INTERFACE javax.jms.Session
METHOD createProducer
HELPER io.opentracing.contrib.agent.helper.JMSMessageProducerHelper
@@ -117,7 +117,7 @@ DO
ENDRULE
-RULE jms consumer
+RULE opentracing-jms-2_consumer
INTERFACE javax.jms.Session
METHOD createConsumer
HELPER io.opentracing.contrib.agent.helper.JMSMessageConsumerHelper

ADD
dd-java-agent/src/test/java/io/opentracing/contrib/agent/InstrumentationCheckerTest.java
+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<String, List<Map<String, String>>> rules = FactoryUtils.loadConfigFromResource("supported-version-test.yaml", Map.class);
+ Map<String, String> frameworks = new HashMap<String, String>() {{
+ 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<String> rules = InstrumentationChecker.getUnsupportedRules();
+ assertThat(rules.size()).isEqualTo(3);
+ assertThat(rules).containsExactlyInAnyOrder("unsupportedRuleOne", "unsupportedRuleTwo", "unsupportedRuleThree");
+
+
+ }
+
+}
\ No newline at end of file

ADD
dd-java-agent/src/test/resources/supported-version-test.yaml
+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

MODIFY
dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml
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

refactoring the version checker