原文:http://blog.mygraphql.com/wordpress/?p=112git
经过实现 graphql.execution.instrumentation.Instrumentation
接口,你能够在执行查询的过程当中注入定制代码。并能够修改运行期的行为。github
它的主要用途是性能监控和定制日志,但也能够完成其它任务。app
当建立 `Graphql
对象时,能够绑定相关的 Instrumentation
。ide
GraphQL.newGraphQL(schema) .instrumentation(new TracingInstrumentation()) .build();
要实现 Instrumentation
,须要实现多个 “begin”
开头的方法。这方法会在查询执行过程当中,每一步骤开始前被调用。wordpress
全部回调方法,都应该返回graphql.execution.instrumentation.InstrumentationContext
对象,这个对象会在本步骤完成时被回调用,回调用时会告知数据的获取结果,若是出错,能够获取
Throwable 对象。.性能
下面是一个定制的 Instrumentation
。做用是测量执行时间。fetch
class CustomInstrumentationState implements InstrumentationState { private Map<String, Object> anyStateYouLike = new HashMap<>(); void recordTiming(String key, long time) { anyStateYouLike.put(key, time); } } class CustomInstrumentation implements Instrumentation { @Override public InstrumentationState createState() { // // instrumentation state is passed during each invocation of an Instrumentation method // and allows you to put stateful data away and reference it during the query execution // return new CustomInstrumentationState(); } @Override public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExecutionParameters parameters) { long startNanos = System.nanoTime(); return (result, throwable) -> { CustomInstrumentationState state = parameters.getInstrumentationState(); state.recordTiming(parameters.getQuery(), System.nanoTime() - startNanos); }; } @Override public InstrumentationContext<Document> beginParse(InstrumentationExecutionParameters parameters) { // // You MUST return a non null object but it does not have to do anything and hence // you use this class to return a no-op object // return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public InstrumentationContext<List<ValidationError>> beginValidation(InstrumentationValidationParameters parameters) { return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public InstrumentationContext<ExecutionResult> beginDataFetch(InstrumentationDataFetchParameters parameters) { return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public InstrumentationContext<CompletableFuture<ExecutionResult>> beginExecutionStrategy(InstrumentationExecutionStrategyParameters parameters) { return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public InstrumentationContext<ExecutionResult> beginField(InstrumentationFieldParameters parameters) { return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters) { return new NoOpInstrumentation.NoOpInstrumentationContext<>(); } @Override public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters) { // // this allows you to intercept the data fetcher used ot fetch a field and provide another one, perhaps // that enforces certain behaviours or has certain side effects on the data // return dataFetcher; } @Override public CompletableFuture<ExecutionResult> instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters) { // // this allows you to instrument the execution result some how. For example the Tracing support uses this to put // the `extensions` map of data in place // return CompletableFuture.completedFuture(executionResult); } }
你能够用 graphql.execution.instrumentation.ChainedInstrumentation
把多个 Instrumentation
链接起来。这些 Instrumentation
对象会按顺序被调用。ui
List<Instrumentation> chainedList = new ArrayList<>(); chainedList.add(new FooInstrumentation()); chainedList.add(new BarInstrumentation()); ChainedInstrumentation chainedInstrumentation = new ChainedInstrumentation(chainedList); GraphQL.newGraphQL(schema) .instrumentation(chainedInstrumentation) .build();
graphql.execution.instrumentation.tracing.TracingInstrumentation
是一个能够收集跟踪信息的拦截器。this
它按照 Apollo 跟踪格式 https://github.com/apollograp...
来收集跟踪信息。日志
详细的跟踪信息( tracing map)会放在查询结果的 extensions(扩展)
部分。
如如下的查询:
query { hero { name friends { name } } }
会返回以下的结果:
{ "data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } }, "extensions": { "tracing": { "version": 1, "startTime": "2017-08-14T23:13:39.362Z", "endTime": "2017-08-14T23:13:39.497Z", "duration": 135589186, "execution": { "resolvers": [ { "path": [ "hero" ], "parentType": "Query", "returnType": "Character", "fieldName": "hero", "startOffset": 105697585, "duration": 79111240 }, { "path": [ "hero", "name" ], "parentType": "Droid", "returnType": "String", "fieldName": "name", "startOffset": 125010028, "duration": 20213 }, { "path": [ "hero", "friends" ], "parentType": "Droid", "returnType": "[Character]", "fieldName": "friends", "startOffset": 133352819, "duration": 7927560 }, { "path": [ "hero", "friends", 0, "name" ], "parentType": "Human", "returnType": "String", "fieldName": "name", "startOffset": 134105887, "duration": 6783 }, { "path": [ "hero", "friends", 1, "name" ], "parentType": "Human", "returnType": "String", "fieldName": "name", "startOffset": 134725922, "duration": 7016 }, { "path": [ "hero", "friends", 2, "name" ], "parentType": "Human", "returnType": "String", "fieldName": "name", "startOffset": 134875089, "duration": 6342 } ] } } } }
graphql.execution.instrumentation.fieldvalidation.FieldValidationInstrumentation
拦截器,能够在执行查询前校验字段和字段参数。若是校验失败,查询将中止,并返回错误信息。
你能够编写本身的FieldValidation
实现,或者直接用SimpleFieldValidation
去为每一个field定义校验逻辑。
ExecutionPath fieldPath = ExecutionPath.parse("/user"); FieldValidation fieldValidation = new SimpleFieldValidation() .addRule(fieldPath, new BiFunction<FieldAndArguments, FieldValidationEnvironment, Optional<GraphQLError>>() { @Override public Optional<GraphQLError> apply(FieldAndArguments fieldAndArguments, FieldValidationEnvironment environment) { String nameArg = fieldAndArguments.getFieldArgument("name"); if (nameArg.length() > 255) { return Optional.of(environment.mkError("Invalid user name", fieldAndArguments)); } return Optional.empty(); } }); FieldValidationInstrumentation instrumentation = new FieldValidationInstrumentation( fieldValidation ); GraphQL.newGraphQL(schema) .instrumentation(instrumentation) .build();