33import com .datadoghq .trace .resolver .FactoryUtils ;
44import com .fasterxml .jackson .annotation .JsonProperty ;
55import com .fasterxml .jackson .core .type .TypeReference ;
6- import java .io .File ;
76import java .lang .reflect .Method ;
87import java .util .ArrayList ;
98import java .util .Collections ;
10- import java .util .HashMap ;
119import java .util .List ;
1210import java .util .Map ;
13- import java .util .regex .Matcher ;
14- import java .util .regex .Pattern ;
1511import lombok .Data ;
1612import lombok .extern .slf4j .Slf4j ;
1713
2319public class InstrumentationChecker {
2420
2521 private static final String CONFIG_FILE = "dd-trace-supported-framework" ;
26- private static InstrumentationChecker INSTANCE ;
2722
2823 private final Map <String , List <ArtifactSupport >> rules ;
29- private final Map <String , String > frameworks ;
30-
31- private final ClassLoader classLoader ;
3224
3325 /* For testing purpose */
3426 InstrumentationChecker (
3527 final Map <String , List <ArtifactSupport >> rules , final Map <String , String > frameworks ) {
3628 this .rules = rules ;
37- this .frameworks = frameworks ;
38- this .classLoader = ClassLoader .getSystemClassLoader ();
39- INSTANCE = this ;
4029 }
4130
42- private InstrumentationChecker (final ClassLoader classLoader ) {
43- this .classLoader = classLoader ;
31+ public InstrumentationChecker () {
4432 rules =
4533 FactoryUtils .loadConfigFromResource (
4634 CONFIG_FILE , new TypeReference <Map <String , List <ArtifactSupport >>>() {});
47- frameworks = scanLoadedLibraries ();
48- }
49-
50- /**
51- * Return a list of unsupported rules regarding loading deps
52- *
53- * @return the list of unsupported rules
54- * @param classLoader
55- */
56- public static synchronized List <String > getUnsupportedRules (final ClassLoader classLoader ) {
57-
58- if (INSTANCE == null ) {
59- INSTANCE = new InstrumentationChecker (classLoader );
60- }
61-
62- return INSTANCE .doGetUnsupportedRules ();
63- }
64-
65- private static Map <String , String > scanLoadedLibraries () {
66-
67- final Map <String , String > frameworks = new HashMap <>();
68-
69- // Scan classpath provided jars
70- final List <File > jars = getJarFiles (System .getProperty ("java.class.path" ));
71- for (final File file : jars ) {
72-
73- final String jarName = file .getName ();
74- final String version = extractJarVersion (jarName );
75-
76- if (version != null ) {
77-
78- // Extract artifactId
79- final String artifactId = file .getName ().substring (0 , jarName .indexOf (version ) - 1 );
80-
81- // Store it
82- frameworks .put (artifactId , version );
83- }
84- }
85- log .debug ("{} libraries found in the class-path" , frameworks .size ());
86-
87- return frameworks ;
88- }
89-
90- private static List <File > getJarFiles (final String paths ) {
91- final List <File > filesList = new ArrayList <>();
92- for (final String path : paths .split (File .pathSeparator )) {
93- final File file = new File (path );
94- if (file .isDirectory ()) {
95- recurse (filesList , file );
96- } else {
97- if (file .getName ().endsWith (".jar" )) {
98- log .trace ("{} found in the classpath" , file .getName ());
99- filesList .add (file );
100- }
101- }
102- }
103- return filesList ;
104- }
105-
106- private static void recurse (final List <File > filesList , final File f ) {
107- final File [] list = f .listFiles ();
108- for (final File file : list ) {
109- getJarFiles (file .getPath ());
110- }
11135 }
11236
113- private static String extractJarVersion (final String jarName ) {
114-
115- final Pattern versionPattern = Pattern .compile ("-(\\ d+\\ ..+)\\ .jar" );
116- final Matcher matcher = versionPattern .matcher (jarName );
117- if (matcher .find ()) {
118- return matcher .group (1 );
119- } else {
120- return null ;
121- }
122- }
123-
124- private List <String > doGetUnsupportedRules () {
37+ public List <String > getUnsupportedRules (ClassLoader classLoader ) {
38+ log .debug ("Checking rule compatibility on classloader {}" , classLoader );
12539
12640 final List <String > unsupportedRules = new ArrayList <>();
12741 for (final String rule : rules .keySet ()) {
@@ -131,58 +45,54 @@ private List<String> doGetUnsupportedRules() {
13145 for (final ArtifactSupport check : rules .get (rule )) {
13246 log .debug ("Checking rule {}" , check );
13347
134- boolean matched = true ;
135- for (final Map .Entry <String , String > identifier :
136- check .identifyingPresentClasses .entrySet ()) {
137- final boolean classPresent = isClassPresent (identifier .getKey ());
138- if (!classPresent ) {
139- log .debug ("Instrumentation {} not applied due to missing class {}." , rule , identifier );
140- } else {
141- String identifyingMethod = identifier .getValue ();
142- if (identifyingMethod != null && !identifyingMethod .isEmpty ()) {
143- Class clazz = getClassIfPresent (identifier .getKey (), classLoader );
144- // already confirmed above the class is there.
145- Method [] declaredMethods = clazz .getDeclaredMethods ();
146- boolean methodFound = false ;
147- for (Method m : declaredMethods ) {
148- if (m .getName ().equals (identifyingMethod )) {
149- methodFound = true ;
150- break ;
48+ boolean matched =
49+ (check .identifyingPresentClasses != null
50+ && !check .identifyingPresentClasses .entrySet ().isEmpty ())
51+ || (check .identifyingMissingClasses != null
52+ && !check .identifyingMissingClasses .isEmpty ());
53+ if (check .identifyingPresentClasses != null ) {
54+ for (final Map .Entry <String , String > identifier :
55+ check .identifyingPresentClasses .entrySet ()) {
56+ final boolean classPresent = isClassPresent (identifier .getKey (), classLoader );
57+ if (!classPresent ) {
58+ log .debug (
59+ "Instrumentation {} not applied due to missing class {}." , rule , identifier );
60+ } else {
61+ String identifyingMethod = identifier .getValue ();
62+ if (identifyingMethod != null && !identifyingMethod .isEmpty ()) {
63+ Class clazz = getClassIfPresent (identifier .getKey (), classLoader );
64+ // already confirmed above the class is there.
65+ Method [] declaredMethods = clazz .getDeclaredMethods ();
66+ boolean methodFound = false ;
67+ for (Method m : declaredMethods ) {
68+ if (m .getName ().equals (identifyingMethod )) {
69+ methodFound = true ;
70+ break ;
71+ }
72+ }
73+ if (!methodFound ) {
74+ log .debug (
75+ "Instrumentation {} not applied due to missing method {}.{}" ,
76+ rule ,
77+ identifier .getKey (),
78+ identifyingMethod );
79+ matched = false ;
15180 }
152- }
153- if (!methodFound ) {
154- log .debug (
155- "Instrumentation {} not applied due to missing method {}.{}" ,
156- rule ,
157- identifier .getKey (),
158- identifyingMethod );
159- matched = false ;
16081 }
16182 }
83+ matched &= classPresent ;
16284 }
163- matched &= classPresent ;
164- }
165- for (final String identifyingClass : check .identifyingMissingClasses ) {
166- final boolean classMissing = !isClassPresent (identifyingClass );
167- if (!classMissing ) {
168- log .debug (
169- "Instrumentation {} not applied due to present class {}." , rule , identifyingClass );
170- }
171- matched &= classMissing ;
17285 }
173-
174- final boolean useVersionMatching =
175- frameworks .containsKey (check .artifact )
176- && check .identifyingMissingClasses .isEmpty ()
177- && check .identifyingPresentClasses .isEmpty ();
178- if (useVersionMatching ) {
179- // If no classes to scan, fall back on version regex.
180- matched = Pattern .matches (check .supportedVersion , frameworks .get (check .artifact ));
181- if (!matched ) {
182- log .debug (
183- "Library conflict: supported_version={}, actual_version={}" ,
184- check .supportedVersion ,
185- frameworks .get (check .artifact ));
86+ if (check .identifyingMissingClasses != null ) {
87+ for (final String identifyingClass : check .identifyingMissingClasses ) {
88+ final boolean classMissing = !isClassPresent (identifyingClass , classLoader );
89+ if (!classMissing ) {
90+ log .debug (
91+ "Instrumentation {} not applied due to present class {}." ,
92+ rule ,
93+ identifyingClass );
94+ }
95+ matched &= classMissing ;
18696 }
18797 }
18898
@@ -201,10 +111,6 @@ private List<String> doGetUnsupportedRules() {
201111 return unsupportedRules ;
202112 }
203113
204- private boolean isClassPresent (final String identifyingPresentClass ) {
205- return isClassPresent (identifyingPresentClass , classLoader );
206- }
207-
208114 static boolean isClassPresent (final String identifyingPresentClass , ClassLoader classLoader ) {
209115 return getClassIfPresent (identifyingPresentClass , classLoader ) != null ;
210116 }
0 commit comments