Add version checking via class/method for jetty
MODIFY
buildSrc/src/main/groovy/VersionScanPlugin.groovy
buildSrc/src/main/groovy/VersionScanPlugin.groovy
@@ -139,6 +139,12 @@ class VersionScanPlugin implements Plugin<Project> {
def errors = []
for (String className : verifyPresent.keySet()) {
+ if (project.versionScan.scanMethods && verifyPresent.get(className) == null) {
+ throw new AssertionError("When 'scanMethods' is enabled, a method must be configured for '$className'")
+ } else if (!project.versionScan.scanMethods && verifyPresent.get(className) != null) {
+ throw new AssertionError("When 'scanMethods' is not enabled, configured method must be null for '$className'")
+ }
+
String identifier = project.versionScan.scanMethods ? "$className|${verifyPresent.get(className)}" : className
if (!keyPresent.get().contains(identifier)) {
errors << "not a 'keyPresent' identifier: $identifier"

ADD
dd-java-agent/integrations/jetty/jetty.gradle
+apply plugin: 'version-scan'
+
+versionScan {
+ group = "org.eclipse.jetty"
+ module = "jetty-server"
+ versions = "[8.0,)"
+ legacyGroup = "org.mortbay.jetty"
+ legacyModule = "jetty"
+ scanMethods = true
+ verifyPresent = [
+ "org.eclipse.jetty.server.ServletRequestHttpWrapper": "getPart",
+ ]
+}

MODIFY
dd-java-agent/src/main/java/com/datadoghq/trace/agent/InstrumentationChecker.java
dd-java-agent/src/main/java/com/datadoghq/trace/agent/InstrumentationChecker.java
@@ -4,6 +4,7 @@ import com.datadoghq.trace.resolver.FactoryUtils;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import java.io.File;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -131,11 +132,33 @@ public class InstrumentationChecker {
log.debug("Checking rule {}", check);
boolean matched = true;
- for (final String identifyingClass : check.identifyingPresentClasses) {
- final boolean classPresent = isClassPresent(identifyingClass);
+ for (final Map.Entry<String, String> identifier :
+ check.identifyingPresentClasses.entrySet()) {
+ final boolean classPresent = isClassPresent(identifier.getKey());
if (!classPresent) {
+ log.debug("Instrumentation {} not applied due to missing class {}.", rule, identifier);
+ } else {
+ String identifyingMethod = identifier.getValue();
+ if (identifyingMethod != null && !identifyingMethod.isEmpty()) {
+ Class clazz = getClassIfPresent(identifier.getKey(), classLoader);
+ // already confirmed above the class is there.
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ boolean methodFound = false;
+ for (Method m : declaredMethods) {
+ if (m.getName().equals(identifyingMethod)) {
+ methodFound = true;
+ break;
+ }
+ }
+ if (!methodFound) {
log.debug(
- "Instrumentation {} not applied due to missing class {}.", rule, identifyingClass);
+ "Instrumentation {} not applied due to missing method {}.{}",
+ rule,
+ identifier.getKey(),
+ identifyingMethod);
+ matched = false;
+ }
+ }
}
matched &= classPresent;
}
@@ -183,11 +206,14 @@ public class InstrumentationChecker {
}
static boolean isClassPresent(final String identifyingPresentClass, ClassLoader classLoader) {
+ return getClassIfPresent(identifyingPresentClass, classLoader) != null;
+ }
+
+ static Class getClassIfPresent(final String identifyingPresentClass, ClassLoader classLoader) {
try {
- return identifyingPresentClass != null
- && Class.forName(identifyingPresentClass, false, classLoader) != null;
- } catch (final ClassNotFoundException e) {
- return false;
+ return Class.forName(identifyingPresentClass, false, classLoader);
+ } catch (final Exception e) {
+ return null;
}
}
@@ -199,7 +225,7 @@ public class InstrumentationChecker {
private String supportedVersion;
@JsonProperty("identifying_present_classes")
- private List<String> identifyingPresentClasses = Collections.emptyList();
+ private Map<String, String> identifyingPresentClasses = Collections.emptyMap();
@JsonProperty("identifying_missing_classes")
private List<String> identifyingMissingClasses = Collections.emptyList();

MODIFY
dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml
dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml
### - artifact: <artifactId> # the artifact name to be tested
### supported_version: # a regex expression to express the version required by the rule
### identifying_present_classes: # a list of classes that distinctly identify the range of supported libraries
-### - some.key.FrameworkClass # only if missing, supported_version regex is used.
+### some.key.FrameworkClass: orMethod # only if missing, supported_version regex is used.
### - ...
opentracing-apache-httpclient:
- artifact: httpclient
supported_version: 4\.[3|4|5]\..*
identifying_present_classes:
- - org.apache.http.conn.SchemePortResolver
- - org.apache.http.conn.ssl.SSLContexts
+ org.apache.http.conn.SchemePortResolver:
+ org.apache.http.conn.ssl.SSLContexts:
- artifact: commons-httpclient
supported_version: none
@@ -21,82 +21,83 @@ opentracing-aws-sdk:
- artifact: aws-java-sdk
supported_version: 1\.11\..*
identifying_present_classes:
- - com.amazonaws.http.client.HttpClientFactory
- - com.amazonaws.http.apache.utils.ApacheUtils
- - com.amazonaws.http.request.HttpRequestFactory
+ com.amazonaws.http.client.HttpClientFactory:
+ com.amazonaws.http.apache.utils.ApacheUtils:
+ com.amazonaws.http.request.HttpRequestFactory:
opentracing-cassandra-driver:
- artifact: cassandra-driver-core
supported_version: 3\.2.*
identifying_present_classes:
- - com.datastax.driver.core.utils.MoreObjects
- - com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions
- - com.datastax.driver.core.GuavaCompatibility
+ com.datastax.driver.core.utils.MoreObjects:
+ com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions:
+ com.datastax.driver.core.GuavaCompatibility:
opentracing-jms-2_producer:
- artifact: javax.jms-api
supported_version: 2\..*
identifying_present_classes:
- - javax.jms.JMSContext
- - javax.jms.CompletionListener
+ javax.jms.JMSContext:
+ javax.jms.CompletionListener:
opentracing-jms-2_consumer:
- artifact: javax.jms-api
supported_version: 2\..*
identifying_present_classes:
- - javax.jms.JMSContext
- - javax.jms.CompletionListener
+ javax.jms.JMSContext:
+ javax.jms.CompletionListener:
opentracing-mongo-driver:
- artifact: mongo-java-driver
supported_version: 3\..*
identifying_present_classes:
- - com.mongodb.operation.AsyncReadOperation
- - com.mongodb.client.model.MapReduceAction
+ com.mongodb.operation.AsyncReadOperation:
+ com.mongodb.client.model.MapReduceAction:
- artifact: mongodb-driver-async
supported_version: 3\..*
identifying_present_classes:
- - com.mongodb.operation.AsyncReadOperation
- - com.mongodb.client.model.MapReduceAction
+ com.mongodb.operation.AsyncReadOperation:
+ com.mongodb.client.model.MapReduceAction:
opentracing-mongo-driver-helper:
- artifact: mongo-java-driver
supported_version: 3\..*
identifying_present_classes:
- - com.mongodb.operation.AsyncReadOperation
- - com.mongodb.client.model.MapReduceAction
+ com.mongodb.operation.AsyncReadOperation:
+ com.mongodb.client.model.MapReduceAction:
- artifact: mongodb-driver-async
supported_version: 3\..*
identifying_present_classes:
- - com.mongodb.operation.AsyncReadOperation
- - com.mongodb.client.model.MapReduceAction
+ com.mongodb.operation.AsyncReadOperation:
+ com.mongodb.client.model.MapReduceAction:
opentracing-okhttp3:
- artifact: okhttp
supported_version: 3\..*
identifying_present_classes:
- - okhttp3.Cookie
- - okhttp3.ConnectionPool
- - okhttp3.Headers
+ okhttp3.Cookie:
+ okhttp3.ConnectionPool:
+ okhttp3.Headers:
opentracing-web-servlet-filter_jetty:
- artifact: jetty-server
supported_version: (8\.|9\.).*
-# identifying_present_classes:
+ identifying_present_classes:
+ org.eclipse.jetty.server.ServletRequestHttpWrapper: getPart
opentracing-web-servlet-filter_tomcat:
- artifact: opentracing-web-servlet-filter_tomcat
supported_version: (8\.|9\.).*
identifying_present_classes:
- - org.apache.catalina.WebResource
- - org.apache.catalina.webresources.TrackedInputStream
- - org.apache.catalina.webresources.AbstractArchiveResource
+ org.apache.catalina.WebResource:
+ org.apache.catalina.webresources.TrackedInputStream:
+ org.apache.catalina.webresources.AbstractArchiveResource:
- artifact: opentracing-web-servlet-filter_tomcat
supported_version: (8\.|9\.).*
identifying_present_classes:
- - org.apache.catalina.WebResource
- - org.apache.catalina.webresources.TrackedInputStream
- - org.apache.catalina.webresources.AbstractArchiveResource
+ org.apache.catalina.WebResource:
+ org.apache.catalina.webresources.TrackedInputStream:
+ org.apache.catalina.webresources.AbstractArchiveResource:

MODIFY
dd-java-agent/src/test/groovy/com/datadoghq/trace/agent/InstrumentationCheckerTest.groovy
dd-java-agent/src/test/groovy/com/datadoghq/trace/agent/InstrumentationCheckerTest.groovy
@@ -24,7 +24,9 @@ class InstrumentationCheckerTest extends Specification {
rules.sort() == ["unsupportedRuleOne", "unsupportedRuleThree", "unsupportedRuleTwo"]
}
- static class DemoClass1 {}
+ static class DemoClass1 {
+ void testMethod(String arg) {}
+ }
static class DemoClass2 {}

MODIFY
dd-java-agent/src/test/resources/supported-version-test.yaml
dd-java-agent/src/test/resources/supported-version-test.yaml
@@ -4,38 +4,36 @@ unsupportedRuleOne:
- artifact: artifact-2
supported_version: none
- identifying_present_classes:
- -
unsupportedRuleTwo:
- artifact: artifact-1
supported_version: 2\.3\.
identifying_present_classes:
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$MissingClass
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1: missingMethod
supportedRuleOne:
- artifact: artifact-3
supported_version: 5\..*
identifying_present_classes:
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass2
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass3
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1:
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass2:
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass3:
supportedRuleTwo:
- artifact: artifact-1
supported_version: 1\.2\.3\..*
identifying_present_classes:
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass2
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1: testMethod
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass2:
- artifact: artifact-2
supported_version: 4\..*
identifying_present_classes:
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass3
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass3: missingMethod
unsupportedRuleThree:
- artifact: foo
supported_version: 1
identifying_present_classes:
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1
- - com.datadoghq.trace.agent.InstrumentationCheckerTest$MissingClass
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$DemoClass1:
+ com.datadoghq.trace.agent.InstrumentationCheckerTest$MissingClass:

MODIFY
settings.gradle
settings.gradle
@@ -14,6 +14,7 @@ include ':dd-trace-annotations'
include ':dd-java-agent:integrations:apache-httpclient'
include ':dd-java-agent:integrations:aws-sdk'
include ':dd-java-agent:integrations:cassandra'
+include ':dd-java-agent:integrations:jetty'
include ':dd-java-agent:integrations:jms'
include ':dd-java-agent:integrations:mongo'
include ':dd-java-agent:integrations:mongo-async'

Add version checking via class/method for jetty