原文: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();