22
33import graphql .agent .result .ExecutionTrackingResult ;
44import graphql .execution .ExecutionContext ;
5+ import graphql .execution .ExecutionId ;
56import graphql .execution .ExecutionStrategyParameters ;
67import graphql .execution .ResultPath ;
8+ import graphql .schema .DataFetchingEnvironment ;
79import net .bytebuddy .agent .builder .AgentBuilder ;
810import net .bytebuddy .asm .Advice ;
11+ import net .bytebuddy .implementation .bytecode .assign .Assigner ;
12+ import org .dataloader .DataLoader ;
913
1014import java .lang .instrument .Instrumentation ;
15+ import java .util .Map ;
16+ import java .util .Set ;
1117import java .util .concurrent .CompletableFuture ;
18+ import java .util .concurrent .ConcurrentHashMap ;
1219
1320import static graphql .agent .result .ExecutionTrackingResult .EXECUTION_TRACKING_KEY ;
1421import static net .bytebuddy .matcher .ElementMatchers .nameMatches ;
1522import static net .bytebuddy .matcher .ElementMatchers .named ;
1623
1724public class GraphQLJavaAgent {
1825
26+ public static class ExecutionData {
27+ public Set <ResultPath > resultPaths = ConcurrentHashMap .newKeySet ();
28+
29+ public Map <ResultPath , DataLoader > resultPathToDataLoader = new ConcurrentHashMap <>();
30+ public Map <DataLoader , String > dataLoaderToName = new ConcurrentHashMap <>();
31+
32+ @ Override
33+ public String toString () {
34+ return "ExecutionData{" +
35+ "resultPathToDataLoader=" + resultPathToDataLoader +
36+ ", dataLoaderToName=" + dataLoaderToName +
37+ '}' ;
38+ }
39+ }
40+
41+ public static final Map <ExecutionId , ExecutionData > executionDataMap = new ConcurrentHashMap <>();
42+ public static final Map <DataLoader , ExecutionId > dataLoaderToExecutionId = new ConcurrentHashMap <>();
43+
1944 public static void agentmain (String agentArgs , Instrumentation inst ) {
2045 System .out .println ("Agent is running" );
2146 new AgentBuilder .Default ()
22- .disableClassFormatChanges ()
47+ .type (named ("graphql.execution.Execution" ))
48+ .transform ((builder , typeDescription , classLoader , module , protectionDomain ) -> {
49+ System .out .println ("transforming " + typeDescription );
50+ return builder
51+ .visit (Advice .to (ExecutionAdvice .class ).on (nameMatches ("executeOperation" )));
52+
53+ })
2354 .type (named ("graphql.execution.ExecutionStrategy" ))
2455 .transform ((builder , typeDescription , classLoader , module , protectionDomain ) -> {
2556 System .out .println ("Transforming " + typeDescription );
2657 return builder
2758 .visit (Advice .to (DataFetcherInvokeAdvice .class ).on (nameMatches ("invokeDataFetcher" )));
2859 })
29- .installOn (inst );
30-
31- new AgentBuilder .Default ()
32- .disableClassFormatChanges ()
33- .type (named ("graphql.execution.Execution" ))
60+ .type (named ("org.dataloader.DataLoaderRegistry" ))
3461 .transform ((builder , typeDescription , classLoader , module , protectionDomain ) -> {
3562 System .out .println ("transforming " + typeDescription );
3663 return builder
37- .visit (Advice .to (ExecutionAdvice .class ).on (nameMatches ("executeOperation" )));
38- }).installOn (inst );
39-
40- new AgentBuilder .Default ()
41- .disableClassFormatChanges ()
42- .with (AgentBuilder .RedefinitionStrategy .DISABLED )
43- .type (named ("org.dataloader.DataLoaderRegistry" ))
64+ .visit (Advice .to (DataLoaderRegistryAdvice .class ).on (nameMatches ("dispatchAll" )));
65+ })
66+ .type (named ("org.dataloader.DataLoader" ))
4467 .transform ((builder , typeDescription , classLoader , module , protectionDomain ) -> {
4568 System .out .println ("transforming " + typeDescription );
4669 return builder
47- .visit (Advice .to (DataLoaderRegistryAdvice .class ).on (nameMatches ("dispatchAll" )));
48- }).installOn (inst );
70+ .visit (Advice .to (DataLoaderAdvice .class ).on (nameMatches ("load" )));
71+ })
72+ .type (named ("graphql.schema.DataFetchingEnvironmentImpl" ))
73+ .transform ((builder , typeDescription , classLoader , module , protectionDomain ) -> {
74+ System .out .println ("transforming " + typeDescription );
75+ return builder
76+ .visit (Advice .to (DataFetchingEnvironmentAdvice .class ).on (nameMatches ("getDataLoader" )));
77+ })
78+ .installOn (inst );
79+
4980 }
5081}
5182
83+ class DataFetchingEnvironmentAdvice {
84+
85+
86+ @ Advice .OnMethodExit
87+ public static void getDataLoader (@ Advice .Argument (0 ) String dataLoaderName ,
88+ @ Advice .This (typing = Assigner .Typing .DYNAMIC ) DataFetchingEnvironment dataFetchingEnvironment ,
89+ @ Advice .Return (readOnly = false , typing = Assigner .Typing .DYNAMIC ) DataLoader dataLoader ) {
90+ GraphQLJavaAgent .ExecutionData executionData = GraphQLJavaAgent .executionDataMap .get (dataFetchingEnvironment .getExecutionId ());
91+ System .out .println ("execution data: " + executionData );
92+ executionData .resultPathToDataLoader .put (dataFetchingEnvironment .getExecutionStepInfo ().getPath (), dataLoader );
93+ executionData .dataLoaderToName .put (dataLoader , dataLoaderName );
94+ GraphQLJavaAgent .dataLoaderToExecutionId .put (dataLoader , dataFetchingEnvironment .getExecutionId ());
95+
96+ System .out .println (dataLoaderName + " > " + dataLoader );
97+ }
98+
99+ }
100+
101+
102+ class DataLoaderAdvice {
103+
104+ @ Advice .OnMethodEnter
105+ public static void load (@ Advice .This (typing = Assigner .Typing .DYNAMIC ) Object dataLoader ) {
106+ ExecutionId executionId = GraphQLJavaAgent .dataLoaderToExecutionId .get (dataLoader );
107+ String dataLoaderName = GraphQLJavaAgent .executionDataMap .get (executionId ).dataLoaderToName .get (dataLoader );
108+ System .out .println ("dataloader " + dataLoaderName + " load for execution " + executionId );
109+ }
110+
111+ }
112+
52113class DataLoaderRegistryAdvice {
53114
54115 @ Advice .OnMethodEnter
55116 public static void dispatchAll () {
117+ // StackWalker instance = StackWalker.getInstance();
118+ // instance.forEach(stackFrame -> {
119+ // System.out.println(stackFrame.getClassName() + " " + stackFrame.getMethodName() + " " + stackFrame.getLineNumber());
120+ // });
56121 System .out .println ("calling dispatchAll" );
57122 }
58123
@@ -62,14 +127,22 @@ class ExecutionAdvice {
62127
63128 @ Advice .OnMethodEnter
64129 public static void executeOperationEnter (@ Advice .Argument (0 ) ExecutionContext executionContext ) {
130+ System .out .println ("execution started for: " + executionContext .getExecutionId ());
65131 executionContext .getGraphQLContext ().put (EXECUTION_TRACKING_KEY , new ExecutionTrackingResult ());
132+ GraphQLJavaAgent .executionDataMap .put (executionContext .getExecutionId (), new GraphQLJavaAgent .ExecutionData ());
133+ }
134+
135+ @ Advice .OnMethodExit
136+ public static void executeOperationExit (@ Advice .Argument (0 ) ExecutionContext executionContext ) {
137+ System .out .println ("execution finished for: " + executionContext .getExecutionId ());
66138 }
67139}
68140
69141class DataFetcherInvokeAdvice {
70142 @ Advice .OnMethodEnter
71143 public static void invokeDataFetcherEnter (@ Advice .Argument (0 ) ExecutionContext executionContext ,
72144 @ Advice .Argument (1 ) ExecutionStrategyParameters parameters ) {
145+
73146 ExecutionTrackingResult executionTrackingResult = executionContext .getGraphQLContext ().get (EXECUTION_TRACKING_KEY );
74147 executionTrackingResult .start (parameters .getPath (), System .nanoTime ());
75148 }
0 commit comments