2929import java .util .List ;
3030import java .util .Map ;
3131
32+ import com .google .common .annotations .VisibleForTesting ;
33+ import com .google .common .base .Splitter ;
34+ import com .microsoft .applicationinsights .agent .internal .config .AgentConfiguration ;
3235import com .microsoft .applicationinsights .agent .internal .config .BuiltInInstrumentation ;
33- import com .microsoft .applicationinsights .agent .internal .config .XmlAgentConfigurationBuilder ;
36+ import com .microsoft .applicationinsights .agent .internal .config .ClassInstrumentationData ;
37+ import com .microsoft .applicationinsights .agent .internal .config .MethodInfo ;
38+ import com .microsoft .applicationinsights .agent .internal .config .builder .XmlAgentConfigurationBuilder ;
39+ import org .glowroot .instrumentation .engine .config .AdviceConfig ;
40+ import org .glowroot .instrumentation .engine .config .AdviceConfig .CaptureKind ;
41+ import org .glowroot .instrumentation .engine .config .ImmutableAdviceConfig ;
42+ import org .glowroot .instrumentation .engine .config .ImmutableInstrumentationDescriptor ;
3443import org .glowroot .instrumentation .engine .config .InstrumentationDescriptor ;
3544import org .glowroot .instrumentation .engine .config .InstrumentationDescriptors ;
45+ import org .objectweb .asm .Type ;
46+ import org .objectweb .asm .commons .Method ;
47+ import org .slf4j .Logger ;
48+ import org .slf4j .LoggerFactory ;
3649
3750class AIAgentXmlLoader {
3851
39- static BuiltInInstrumentation load (File agentJarParentFile ) {
52+ private static final Logger logger = LoggerFactory .getLogger (AIAgentXmlLoader .class );
53+
54+ static AgentConfiguration load (File agentJarParentFile ) {
4055 return new XmlAgentConfigurationBuilder ().parseConfigurationFile (agentJarParentFile .getAbsolutePath ());
4156 }
4257
43- static List <InstrumentationDescriptor > getInstrumentationDescriptors (
44- BuiltInInstrumentation builtInInstrumentation ) throws IOException {
58+ static List <InstrumentationDescriptor > getInstrumentationDescriptors (AgentConfiguration agentConfiguration )
59+ throws IOException {
4560
46- boolean httpEnabled = builtInInstrumentation .isHttpEnabled ();
47- boolean jdbcEnabled = builtInInstrumentation .isJdbcEnabled ();
48- boolean loggingEnabled = builtInInstrumentation .isLoggingEnabled ();
49- boolean redisEnabled = builtInInstrumentation .isJedisEnabled ();
61+ BuiltInInstrumentation builtInConfiguration = agentConfiguration .getBuiltInInstrumentation ();
62+ boolean httpEnabled = builtInConfiguration .isHttpEnabled ();
63+ boolean jdbcEnabled = builtInConfiguration .isJdbcEnabled ();
64+ boolean loggingEnabled = builtInConfiguration .isLoggingEnabled ();
65+ boolean redisEnabled = builtInConfiguration .isJedisEnabled ();
5066
5167 List <InstrumentationDescriptor > instrumentationDescriptors = new ArrayList <>();
5268 for (InstrumentationDescriptor instrumentationDescriptor : InstrumentationDescriptors .read ()) {
@@ -79,6 +95,12 @@ static List<InstrumentationDescriptor> getInstrumentationDescriptors(
7995 break ;
8096 }
8197 }
98+
99+ InstrumentationDescriptor instrumentationDescriptor = buildCustomInstrumentation (agentConfiguration );
100+ if (instrumentationDescriptor != null ) {
101+ System .out .println (instrumentationDescriptor );
102+ instrumentationDescriptors .add (instrumentationDescriptor );
103+ }
82104 return instrumentationDescriptors ;
83105 }
84106
@@ -102,4 +124,106 @@ static Map<String, Map<String, Object>> getInstrumentationConfig(BuiltInInstrume
102124
103125 return instrumentationConfiguration ;
104126 }
127+
128+
129+ private static InstrumentationDescriptor buildCustomInstrumentation (AgentConfiguration agentConfiguration ) {
130+
131+ List <AdviceConfig > adviceConfigs = new ArrayList <>();
132+
133+ for (Map .Entry <String , ClassInstrumentationData > classEntry : agentConfiguration .getClassesToInstrument ()
134+ .entrySet ()) {
135+
136+ String className = classEntry .getKey ();
137+ if (!validJavaFqcn (className )) {
138+ // this is needed to prevent glowroot wildcard from being used for now
139+ // and also to prevent commas in the class name which would cause parsing issues in LocalSpanImpl
140+ logger .warn ("Invalid class name: {}" , className );
141+ continue ;
142+ }
143+ ClassInstrumentationData classInstrumentationData = classEntry .getValue ();
144+
145+ for (Map .Entry <String , Map <String , MethodInfo >> methodNameEntry :
146+ classInstrumentationData .getMethodInfos ().entrySet ()) {
147+
148+ String methodName = methodNameEntry .getKey ();
149+ if (!validJavaIdentifier (methodName )) {
150+ // this is needed to prevent glowroot wildcard from being used for now
151+ // and also to prevent commas in the method name which would cause parsing issues in LocalSpanImpl
152+ logger .warn ("Invalid method name: {}" , methodName );
153+ continue ;
154+ }
155+
156+ Map <String , MethodInfo > methodInfos = methodNameEntry .getValue ();
157+
158+ for (Map .Entry <String , MethodInfo > entry : methodInfos .entrySet ()) {
159+
160+ MethodInfo methodInfo = entry .getValue ();
161+ String signature = entry .getKey ();
162+
163+ ImmutableAdviceConfig .Builder adviceConfig = ImmutableAdviceConfig .builder ()
164+ .className (className )
165+ .methodName (methodName );
166+
167+ if (signature .equals (ClassInstrumentationData .ANY_SIGNATURE_MARKER )) {
168+ adviceConfig .addMethodParameterTypes (".." );
169+ } else {
170+ Method method = new Method (methodName , signature );
171+ for (Type type : method .getArgumentTypes ()) {
172+ adviceConfig .addMethodParameterTypes (type .getClassName ());
173+ }
174+ adviceConfig .methodReturnType (method .getReturnType ().getClassName ());
175+ }
176+
177+ adviceConfigs .add (adviceConfig .captureKind (CaptureKind .LOCAL_SPAN )
178+ // advice config doesn't support threshold, so threshold is embedded into message
179+ // and then parsed out by the agent to decide whether to report telemetry
180+ .spanMessageTemplate (
181+ "__custom," + className + "," + methodName + "," + methodInfo .getThresholdInMS () +
182+ "," + classInstrumentationData .getClassType ())
183+ .timerName ("custom" )
184+ .build ());
185+ }
186+ }
187+ }
188+
189+ if (adviceConfigs .isEmpty ()) {
190+ return null ;
191+ } else {
192+ return ImmutableInstrumentationDescriptor .builder ()
193+ .id ("__custom" )
194+ .name ("__custom" )
195+ .addAllAdviceConfigs (adviceConfigs )
196+ .build ();
197+ }
198+ }
199+
200+ @ VisibleForTesting
201+ static boolean validJavaFqcn (String fqcn ) {
202+ List <String > parts = Splitter .on ('.' ).splitToList (fqcn );
203+ if (parts .isEmpty ()) {
204+ return false ;
205+ }
206+ for (int i = 0 ; i < parts .size () - 1 ; i ++) {
207+ if (!validJavaIdentifier (parts .get (i ))) {
208+ return false ;
209+ }
210+ }
211+ return validJavaIdentifier (parts .get (parts .size () - 1 ));
212+ }
213+
214+ @ VisibleForTesting
215+ static boolean validJavaIdentifier (String identifier ) {
216+ if (identifier .isEmpty ()) {
217+ return false ;
218+ }
219+ if (!Character .isJavaIdentifierStart (identifier .charAt (0 ))) {
220+ return false ;
221+ }
222+ for (int i = 1 ; i < identifier .length (); i ++) {
223+ if (!Character .isJavaIdentifierPart (identifier .charAt (i ))) {
224+ return false ;
225+ }
226+ }
227+ return true ;
228+ }
105229}
0 commit comments