Skip to content

Commit 5774291

Browse files
authored
Merge pull request #270 from bbakerman/269-add-instrumentation-to-execution
#269 - this adds instrumentation to the execution of the graphql query
2 parents 65a26b1 + cd7bb87 commit 5774291

16 files changed

Lines changed: 580 additions & 24 deletions

src/main/java/graphql/GraphQL.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
import graphql.execution.ExecutionIdProvider;
77
import graphql.execution.ExecutionStrategy;
88
import graphql.execution.SimpleExecutionStrategy;
9+
import graphql.execution.instrumentation.Instrumentation;
10+
import graphql.execution.instrumentation.InstrumentationContext;
11+
import graphql.execution.instrumentation.NoOpInstrumentation;
12+
import graphql.execution.instrumentation.parameters.ExecutionParameters;
13+
import graphql.execution.instrumentation.parameters.ValidationParameters;
914
import graphql.language.Document;
1015
import graphql.language.SourceLocation;
1116
import graphql.parser.Parser;
@@ -38,6 +43,7 @@ public ExecutionId provide(String query, String operationName, Object context) {
3843
private final ExecutionStrategy queryStrategy;
3944
private final ExecutionStrategy mutationStrategy;
4045
private final ExecutionIdProvider idProvider;
46+
private final Instrumentation instrumentation;
4147

4248

4349
/**
@@ -76,14 +82,15 @@ public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy) {
7682
* @deprecated use the {@link #newGraphQL(GraphQLSchema)} builder instead. This will be removed in a future version.
7783
*/
7884
public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy) {
79-
this(graphQLSchema,queryStrategy,mutationStrategy, DEFAULT_EXECUTION_ID_PROVIDER);
85+
this(graphQLSchema,queryStrategy,mutationStrategy, DEFAULT_EXECUTION_ID_PROVIDER, NoOpInstrumentation.INSTANCE);
8086
}
8187

82-
private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, ExecutionIdProvider idProvider) {
88+
private GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, ExecutionIdProvider idProvider, Instrumentation instrumentation) {
8389
this.graphQLSchema = assertNotNull(graphQLSchema,"queryStrategy must be non null");
8490
this.queryStrategy = assertNotNull(queryStrategy, "queryStrategy must be non null");
8591
this.idProvider = assertNotNull(idProvider, "idProvider must be non null");
8692
this.mutationStrategy = mutationStrategy;
93+
this.instrumentation = instrumentation;
8794
}
8895

8996
/**
@@ -103,6 +110,7 @@ public static class Builder {
103110
private ExecutionStrategy queryExecutionStrategy = new SimpleExecutionStrategy();
104111
private ExecutionStrategy mutationExecutionStrategy = new SimpleExecutionStrategy();
105112
private ExecutionIdProvider idProvider = DEFAULT_EXECUTION_ID_PROVIDER;
113+
private Instrumentation instrumentation = NoOpInstrumentation.INSTANCE;
106114

107115

108116
public Builder(GraphQLSchema graphQLSchema) {
@@ -124,13 +132,18 @@ public Builder mutationExecutionStrategy(ExecutionStrategy executionStrategy) {
124132
return this;
125133
}
126134

135+
public Builder instrumentation(Instrumentation instrumentation) {
136+
this.instrumentation = assertNotNull(instrumentation, "Instrumentation must be non null");
137+
return this;
138+
}
139+
127140
public Builder executionIdProvider(ExecutionIdProvider executionIdProvider) {
128141
this.idProvider = assertNotNull(executionIdProvider, "ExecutionIdProvider must be non null");
129142
return this;
130143
}
131144

132145
public GraphQL build() {
133-
return new GraphQL(graphQLSchema, queryExecutionStrategy, mutationExecutionStrategy, idProvider);
146+
return new GraphQL(graphQLSchema, queryExecutionStrategy, mutationExecutionStrategy, idProvider, instrumentation);
134147
}
135148
}
136149

@@ -151,29 +164,41 @@ public ExecutionResult execute(String requestString, Object context, Map<String,
151164
}
152165

153166
public ExecutionResult execute(String requestString, String operationName, Object context, Map<String, Object> arguments) {
167+
InstrumentationContext<ExecutionResult> executionCtx = instrumentation.beginExecution(new ExecutionParameters(requestString, operationName, context, arguments));
168+
154169
assertNotNull(arguments, "arguments can't be null");
155170
log.debug("Executing request. operation name: {}. Request: {} ", operationName, requestString);
171+
172+
InstrumentationContext<Document> parseCtx = instrumentation.beginParse(new ExecutionParameters(requestString, operationName, context, arguments));
156173
Parser parser = new Parser();
157174
Document document;
158175
try {
159176
document = parser.parseDocument(requestString);
177+
parseCtx.onEnd(document);
160178
} catch (ParseCancellationException e) {
161179
RecognitionException recognitionException = (RecognitionException) e.getCause();
162180
SourceLocation sourceLocation = new SourceLocation(recognitionException.getOffendingToken().getLine(), recognitionException.getOffendingToken().getCharPositionInLine());
163181
InvalidSyntaxError invalidSyntaxError = new InvalidSyntaxError(sourceLocation);
164182
return new ExecutionResultImpl(Collections.singletonList(invalidSyntaxError));
165183
}
166184

185+
InstrumentationContext<List<ValidationError>> validationCtx = instrumentation.beginValidation(new ValidationParameters(requestString,operationName,context,arguments,document));
186+
167187
Validator validator = new Validator();
168188
List<ValidationError> validationErrors = validator.validateDocument(graphQLSchema, document);
189+
190+
validationCtx.onEnd(validationErrors);
191+
169192
if (validationErrors.size() > 0) {
170193
return new ExecutionResultImpl(validationErrors);
171194
}
172195
ExecutionId executionId = idProvider.provide(requestString, operationName, context);
173196

174-
Execution execution = new Execution(queryStrategy, mutationStrategy);
175-
return execution.execute(executionId, graphQLSchema, context, document, operationName, arguments);
176-
}
197+
Execution execution = new Execution(queryStrategy, mutationStrategy, instrumentation);
198+
ExecutionResult result = execution.execute(executionId, graphQLSchema, context, document, operationName, arguments);
177199

200+
executionCtx.onEnd(result);
178201

202+
return result;
203+
}
179204
}

src/main/java/graphql/execution/Execution.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
import graphql.ExecutionResult;
55
import graphql.GraphQLException;
6+
import graphql.execution.instrumentation.Instrumentation;
7+
import graphql.execution.instrumentation.InstrumentationContext;
8+
import graphql.execution.instrumentation.parameters.DataFetchParameters;
69
import graphql.language.Document;
710
import graphql.language.Field;
811
import graphql.language.OperationDefinition;
@@ -16,17 +19,19 @@
1619

1720
public class Execution {
1821

19-
private FieldCollector fieldCollector = new FieldCollector();
20-
private ExecutionStrategy queryStrategy;
21-
private ExecutionStrategy mutationStrategy;
22+
private final FieldCollector fieldCollector = new FieldCollector();
23+
private final ExecutionStrategy queryStrategy;
24+
private final ExecutionStrategy mutationStrategy;
25+
private final Instrumentation instrumentation;
2226

23-
public Execution(ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy) {
27+
public Execution(ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Instrumentation instrumentation) {
2428
this.queryStrategy = queryStrategy != null ? queryStrategy : new SimpleExecutionStrategy();
2529
this.mutationStrategy = mutationStrategy != null ? mutationStrategy : new SimpleExecutionStrategy();
30+
this.instrumentation = instrumentation;
2631
}
2732

2833
public ExecutionResult execute(ExecutionId executionId, GraphQLSchema graphQLSchema, Object root, Document document, String operationName, Map<String, Object> args) {
29-
ExecutionContextBuilder executionContextBuilder = new ExecutionContextBuilder(new ValuesResolver());
34+
ExecutionContextBuilder executionContextBuilder = new ExecutionContextBuilder(new ValuesResolver(), instrumentation);
3035
ExecutionContext executionContext = executionContextBuilder
3136
.executionId(executionId)
3237
.build(graphQLSchema, queryStrategy, mutationStrategy, root, document, operationName, args);
@@ -49,15 +54,22 @@ private ExecutionResult executeOperation(
4954
ExecutionContext executionContext,
5055
Object root,
5156
OperationDefinition operationDefinition) {
57+
58+
InstrumentationContext<ExecutionResult> dataFetchCtx = instrumentation.beginDataFetch(new DataFetchParameters(executionContext));
59+
5260
GraphQLObjectType operationRootType = getOperationRootType(executionContext.getGraphQLSchema(), operationDefinition);
5361

5462
Map<String, List<Field>> fields = new LinkedHashMap<String, List<Field>>();
5563
fieldCollector.collectFields(executionContext, operationRootType, operationDefinition.getSelectionSet(), new ArrayList<String>(), fields);
5664

65+
ExecutionResult result;
5766
if (operationDefinition.getOperation() == OperationDefinition.Operation.MUTATION) {
58-
return mutationStrategy.execute(executionContext, operationRootType, root, fields);
67+
result = mutationStrategy.execute(executionContext, operationRootType, root, fields);
5968
} else {
60-
return queryStrategy.execute(executionContext, operationRootType, root, fields);
69+
result = queryStrategy.execute(executionContext, operationRootType, root, fields);
6170
}
71+
72+
dataFetchCtx.onEnd(result);
73+
return result;
6274
}
6375
}

src/main/java/graphql/execution/ExecutionContext.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33

44
import graphql.GraphQLError;
5+
import graphql.execution.instrumentation.Instrumentation;
6+
import graphql.execution.instrumentation.NoOpInstrumentation;
57
import graphql.language.FragmentDefinition;
68
import graphql.language.OperationDefinition;
79
import graphql.schema.GraphQLSchema;
@@ -21,8 +23,9 @@ public class ExecutionContext {
2123
private final Map<String, Object> variables;
2224
private final Object root;
2325
private final List<GraphQLError> errors = new CopyOnWriteArrayList<GraphQLError>();
26+
private final Instrumentation instrumentation;
2427

25-
public ExecutionContext(ExecutionId executionId, GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Map<String, FragmentDefinition> fragmentsByName, OperationDefinition operationDefinition, Map<String, Object> variables, Object root) {
28+
public ExecutionContext(Instrumentation instrumentation, ExecutionId executionId, GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Map<String, FragmentDefinition> fragmentsByName, OperationDefinition operationDefinition, Map<String, Object> variables, Object root) {
2629
this.graphQLSchema = graphQLSchema;
2730
this.executionId = executionId;
2831
this.queryStrategy = queryStrategy;
@@ -31,12 +34,18 @@ public ExecutionContext(ExecutionId executionId, GraphQLSchema graphQLSchema, Ex
3134
this.operationDefinition = operationDefinition;
3235
this.variables = variables;
3336
this.root = root;
37+
this.instrumentation = instrumentation;
3438
}
3539

40+
3641
public ExecutionId getExecutionId() {
3742
return executionId;
3843
}
3944

45+
public Instrumentation getInstrumentation() {
46+
return instrumentation;
47+
}
48+
4049
public GraphQLSchema getGraphQLSchema() {
4150
return graphQLSchema;
4251
}

src/main/java/graphql/execution/ExecutionContextBuilder.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graphql.execution;
22

33
import graphql.GraphQLException;
4+
import graphql.execution.instrumentation.Instrumentation;
45
import graphql.language.Definition;
56
import graphql.language.Document;
67
import graphql.language.FragmentDefinition;
@@ -15,21 +16,23 @@
1516
public class ExecutionContextBuilder {
1617

1718
private ValuesResolver valuesResolver;
18-
19+
private Instrumentation instrumentation;
1920
private ExecutionId executionId;
2021

21-
public ExecutionContextBuilder(ValuesResolver valuesResolver) {
22+
public ExecutionContextBuilder(ValuesResolver valuesResolver, Instrumentation instrumentation) {
2223
this.valuesResolver = valuesResolver;
24+
this.instrumentation = instrumentation;
2325
}
2426

27+
2528
public ExecutionContextBuilder executionId(ExecutionId executionId) {
2629
this.executionId = executionId;
2730
return this;
2831
}
2932

3033
public ExecutionContext build(GraphQLSchema graphQLSchema, ExecutionStrategy queryStrategy, ExecutionStrategy mutationStrategy, Object root, Document document, String operationName, Map<String, Object> args) {
3134
// preconditions
32-
assertNotNull(executionId,"You must provide a query identifier");
35+
assertNotNull(executionId, "You must provide a query identifier");
3336

3437
Map<String, FragmentDefinition> fragmentsByName = new LinkedHashMap<String, FragmentDefinition>();
3538
Map<String, OperationDefinition> operationsByName = new LinkedHashMap<String, OperationDefinition>();
@@ -60,6 +63,7 @@ public ExecutionContext build(GraphQLSchema graphQLSchema, ExecutionStrategy que
6063
Map<String, Object> variableValues = valuesResolver.getVariableValues(graphQLSchema, operation.getVariableDefinitions(), args);
6164

6265
return new ExecutionContext(
66+
instrumentation,
6367
executionId,
6468
graphQLSchema,
6569
queryStrategy,

src/main/java/graphql/execution/ExecutionStrategy.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,35 @@
44
import graphql.ExecutionResult;
55
import graphql.ExecutionResultImpl;
66
import graphql.GraphQLException;
7+
import graphql.execution.instrumentation.Instrumentation;
8+
import graphql.execution.instrumentation.InstrumentationContext;
9+
import graphql.execution.instrumentation.parameters.FieldFetchParameters;
10+
import graphql.execution.instrumentation.parameters.FieldParameters;
711
import graphql.language.Field;
8-
import graphql.schema.*;
12+
import graphql.schema.DataFetchingEnvironment;
13+
import graphql.schema.DataFetchingEnvironmentImpl;
14+
import graphql.schema.GraphQLEnumType;
15+
import graphql.schema.GraphQLFieldDefinition;
16+
import graphql.schema.GraphQLInterfaceType;
17+
import graphql.schema.GraphQLList;
18+
import graphql.schema.GraphQLNonNull;
19+
import graphql.schema.GraphQLObjectType;
20+
import graphql.schema.GraphQLScalarType;
21+
import graphql.schema.GraphQLSchema;
22+
import graphql.schema.GraphQLType;
23+
import graphql.schema.GraphQLUnionType;
924
import org.slf4j.Logger;
1025
import org.slf4j.LoggerFactory;
1126

12-
import java.util.*;
27+
import java.util.ArrayList;
28+
import java.util.Arrays;
29+
import java.util.LinkedHashMap;
30+
import java.util.List;
31+
import java.util.Map;
1332

14-
import static graphql.introspection.Introspection.*;
33+
import static graphql.introspection.Introspection.SchemaMetaFieldDef;
34+
import static graphql.introspection.Introspection.TypeMetaFieldDef;
35+
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;
1536

1637
public abstract class ExecutionStrategy {
1738
private static final Logger log = LoggerFactory.getLogger(ExecutionStrategy.class);
@@ -35,15 +56,27 @@ protected ExecutionResult resolveField(ExecutionContext executionContext, GraphQ
3556
executionContext.getGraphQLSchema()
3657
);
3758

59+
Instrumentation instrumentation = executionContext.getInstrumentation();
60+
61+
InstrumentationContext<ExecutionResult> fieldCtx = instrumentation.beginField(new FieldParameters(executionContext, fieldDef));
62+
63+
InstrumentationContext<Object> fetchCtx = instrumentation.beginFieldFetch(new FieldFetchParameters(executionContext, fieldDef, environment));
3864
Object resolvedValue = null;
3965
try {
4066
resolvedValue = fieldDef.getDataFetcher().get(environment);
67+
68+
fetchCtx.onEnd(resolvedValue);
4169
} catch (Exception e) {
4270
log.warn("Exception while fetching data", e);
4371
executionContext.addError(new ExceptionWhileDataFetching(e));
72+
73+
fetchCtx.onEnd(e);
4474
}
4575

46-
return completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);
76+
ExecutionResult result = completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);
77+
78+
fieldCtx.onEnd(result);
79+
return result;
4780
}
4881

4982
protected ExecutionResult completeValue(ExecutionContext executionContext, GraphQLType fieldType, List<Field> fields, Object result) {

0 commit comments

Comments
 (0)