22
33import java .util .Arrays ;
44import java .util .Comparator ;
5+ import java .util .EnumSet ;
56import java .util .HashSet ;
67import java .util .List ;
78import java .util .Map ;
@@ -107,25 +108,67 @@ public HookSite prepare(CtBehavior targetBehavior, Map<String, Object> hookConte
107108 return new HookSite (this , behaviorOrdinal , binding );
108109 }
109110
110- public static void apply (CtBehavior targetBehavior , List <HookSite > hookSites ) {
111+ public enum ApplicationAction {
112+ MARKED ,
113+ INSTRUMENTED
114+ }
115+
116+ private static boolean exceptionLogged = false ;
117+
118+ public static Set <ApplicationAction > apply (CtBehavior targetBehavior , List <HookSite > hookSites , boolean traceClass ) {
119+ Set <ApplicationAction > actions = EnumSet .noneOf (ApplicationAction .class );
111120 MethodInfo methodInfo = targetBehavior .getMethodInfo ();
112121 AnnotationsAttribute attr =
113122 (AnnotationsAttribute )methodInfo .getAttribute (AnnotationsAttribute .visibleTag );
114123
115- // If the behavior is marked as an app method, update the annotation with
116- // the behavior ordinals so the bytebuddy transformer can instrument it.
117- if (attr .getAnnotation (AppMapAppMethod .class .getName ()) != null ) {
118- setBehaviorOrdinals (targetBehavior , hookSites );
119- }
124+ if (attr != null ) {
125+ // If the behavior is marked as an app method, update the annotation with
126+ // the behavior ordinals so the bytebuddy transformer can instrument it.
127+ if (attr .getAnnotation (AppMapAppMethod .class .getName ()) != null ) {
128+ setBehaviorOrdinals (targetBehavior , hookSites );
129+ actions .add (ApplicationAction .MARKED );
130+ if (traceClass ) {
131+ logger .debug ("tracing {}.{}{}" ,
132+ targetBehavior .getDeclaringClass ().getName (),
133+ targetBehavior .getName (),
134+ targetBehavior .getMethodInfo ().getDescriptor ());
135+ }
136+ }
120137
121- // If it's (also) marked as an agent method, it needs to be instrumented
122- // by javassist.
123- if (attr .getAnnotation (AppMapAgentMethod .class .getName ()) != null ) {
124- instrument (targetBehavior , hookSites );
138+ // If it's (also) marked as an agent method, it needs to be instrumented
139+ // by javassist.
140+ if (attr .getAnnotation (AppMapAgentMethod .class .getName ()) != null ) {
141+ try {
142+ instrument (targetBehavior , hookSites );
143+ actions .add (ApplicationAction .INSTRUMENTED );
144+ if (traceClass ) {
145+ String hooks = hookSites .stream ()
146+ .map (h -> h .getHook ().toString ())
147+ .collect (Collectors .joining (", " ));
148+ logger .debug ("{}.{}{} instrumented with hooks: {}" ,
149+ targetBehavior .getDeclaringClass ().getName (),
150+ targetBehavior .getName (),
151+ targetBehavior .getMethodInfo ().getDescriptor (),
152+ hooks );
153+ }
154+ } catch (CannotCompileException | NotFoundException e ) {
155+ String msg = String .format ("failed to instrument %s.%s: %s" ,
156+ targetBehavior .getDeclaringClass ().getName (), targetBehavior .getName (), e .getMessage ());
157+ if (!exceptionLogged ) {
158+ logger .debug (e , msg );
159+ exceptionLogged = true ;
160+ } else {
161+ logger .debug (msg );
162+ }
163+ }
164+ }
125165 }
166+
167+ return actions ;
126168 }
127169
128- public static void instrument (CtBehavior targetBehavior , List <HookSite > hookSites ) {
170+ public static void instrument (CtBehavior targetBehavior , List <HookSite > hookSites )
171+ throws CannotCompileException , NotFoundException {
129172 final CtClass returnType = getReturnType (targetBehavior );
130173 final Boolean returnsVoid = (returnType == CtClass .voidType );
131174
@@ -150,44 +193,36 @@ public static void instrument(CtBehavior targetBehavior, List<HookSite> hookSite
150193
151194 }
152195
153- try {
154- String beforeSrcBlock = beforeSrcBlock (uniqueLocks .toString (),
155- invocations [MethodEvent .METHOD_INVOCATION .getIndex ()]);
156- logger .trace ("{}: beforeSrcBlock:\n {}" , targetBehavior ::getName , beforeSrcBlock ::toString );
157- targetBehavior .insertBefore (
158- beforeSrcBlock );
159-
160- String afterSrcBlock = afterSrcBlock (invocations [MethodEvent .METHOD_RETURN .getIndex ()]);
161- logger .trace ("{}: afterSrcBlock:\n {}" , targetBehavior ::getName , afterSrcBlock ::toString );
162-
163- targetBehavior .insertAfter (
164- afterSrcBlock );
165-
166- ClassPool cp = AppMapClassPool .get ();
167- String exitEarlyCatchSrc = "{com.appland.appmap.process.ThreadLock.current().exit();return;}" ;
168- if (returnsVoid ) {
169- targetBehavior .addCatch (exitEarlyCatchSrc ,
170- cp .get ("com.appland.appmap.process.ExitEarly" ));
171- } else if (!returnType .isPrimitive ()) {
172- exitEarlyCatchSrc = "{com.appland.appmap.process.ThreadLock.current().exit();return("
173- + returnType .getName () + ")$e.getReturnValue();}" ;
174- targetBehavior
175- .addCatch (exitEarlyCatchSrc , cp .get ("com.appland.appmap.process.ExitEarly" ));
176- }
177- logger .trace ("{}: catch1Src:\n {}" , targetBehavior ::getName , exitEarlyCatchSrc ::toString );
178-
179- String catchSrcBlock = catchSrcBlock (invocations [MethodEvent .METHOD_EXCEPTION .getIndex ()]);
180- targetBehavior .addCatch (
181- catchSrcBlock ,
182- cp .get ("java.lang.Throwable" ));
183- logger .trace ("{}: catchSrcBlock:\n {}" , targetBehavior ::getName , catchSrcBlock ::toString );
184-
185- } catch (CannotCompileException e ) {
186- logger .debug (e , "failed to compile {}.{}" , targetBehavior .getDeclaringClass ().getName (),
187- targetBehavior .getName ());
188- } catch (NotFoundException e ) {
189- logger .debug (e );
196+ String beforeSrcBlock = beforeSrcBlock (uniqueLocks .toString (),
197+ invocations [MethodEvent .METHOD_INVOCATION .getIndex ()]);
198+ logger .trace ("{}: beforeSrcBlock:\n {}" , targetBehavior ::getName , beforeSrcBlock ::toString );
199+ targetBehavior .insertBefore (
200+ beforeSrcBlock );
201+
202+ String afterSrcBlock = afterSrcBlock (invocations [MethodEvent .METHOD_RETURN .getIndex ()]);
203+ logger .trace ("{}: afterSrcBlock:\n {}" , targetBehavior ::getName , afterSrcBlock ::toString );
204+
205+ targetBehavior .insertAfter (
206+ afterSrcBlock );
207+
208+ ClassPool cp = AppMapClassPool .get ();
209+ String exitEarlyCatchSrc = "{com.appland.appmap.process.ThreadLock.current().exit();return;}" ;
210+ if (returnsVoid ) {
211+ targetBehavior .addCatch (exitEarlyCatchSrc ,
212+ cp .get ("com.appland.appmap.process.ExitEarly" ));
213+ } else if (!returnType .isPrimitive ()) {
214+ exitEarlyCatchSrc = "{com.appland.appmap.process.ThreadLock.current().exit();return("
215+ + returnType .getName () + ")$e.getReturnValue();}" ;
216+ targetBehavior
217+ .addCatch (exitEarlyCatchSrc , cp .get ("com.appland.appmap.process.ExitEarly" ));
190218 }
219+ logger .trace ("{}: catch1Src:\n {}" , targetBehavior ::getName , exitEarlyCatchSrc ::toString );
220+
221+ String catchSrcBlock = catchSrcBlock (invocations [MethodEvent .METHOD_EXCEPTION .getIndex ()]);
222+ targetBehavior .addCatch (
223+ catchSrcBlock ,
224+ cp .get ("java.lang.Throwable" ));
225+ logger .trace ("{}: catchSrcBlock:\n {}" , targetBehavior ::getName , catchSrcBlock ::toString );
191226 }
192227
193228 private static void setBehaviorOrdinals (CtBehavior behavior ,
0 commit comments