- Instrumentation
- Custom Instrumentation
- Chaining Instrumentation
- Apollo Tracing Instrumentation
- Field Validation Instrumentation
Instrumentation
这个词没找到好的中文对应。以下直接使用本单词。
graphql.execution.instrumentation.Instrumentation接口允许您注入代码,这可以观察一个查询的执行并且还可以更改运行时行为。
这样做的主要用例是支持性能监控和自定义日志记录,但是它也可以用于许多不同的目的。
构建Graphql对象时,可以指定要使用的Instrumentation(如果有的话)。
GraphQL.newGraphQL(schema)
.instrumentation(new TracingInstrumentation())
.build();
Custom Instrumentation
即定制化的Instrumentation。Instrumentation的实现需要实现“begin”步骤方法,这些方法表示graphql查询的执行。
每个步骤都必须返回一个非null的graphql.execution.instrumentation.InstrumentationContext对象,该对象将在步骤完成时被调用,并且将被告知该对象成功或以Throwable失败。
以下是一个基本的自定义Instrumentation,它计算总体执行时间并将其放入有状态对象。
/**
* 自定义的instrumentation实现,用以计算请求处理时间
*
* @author 梦境迷离
* @time 2020年03月31日14:22:24
*/
class CustomInstrumentationState implements InstrumentationState {
private Map<String, Object> anyStateYouLike = new HashMap<>();
void recordTiming(String key, long time) {
anyStateYouLike.put(key, time);
}
}
public class CustomInstrumentation extends SimpleInstrumentation {
@Override
public InstrumentationState createState() {
return new CustomInstrumentationState();
}
@Override
public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExecutionParameters parameters) {
long startNanos = System.nanoTime();
return new SimpleInstrumentationContext<ExecutionResult>() {
@Override
public void onCompleted(ExecutionResult result, Throwable t) {
CustomInstrumentationState state = parameters.getInstrumentationState();
state.recordTiming(parameters.getQuery(), System.nanoTime() - startNanos);
}
};
}
@Override
public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters) {
return dataFetcher;
}
@Override
public CompletableFuture<ExecutionResult> instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters) {
return CompletableFuture.completedFuture(executionResult);
}
}
Chaining Instrumentation
您可以使用graphql.execution.instrumentation.ChainedInstrumentation类将多个Instrumentation对象组合在一起,该类接受Instrumentation对象的列表并按定义的顺序调用它们。
List<Instrumentation> chainedList = new ArrayList<>();
chainedList.add(new FooInstrumentation());
chainedList.add(new BarInstrumentation());
ChainedInstrumentation chainedInstrumentation = new ChainedInstrumentation(chainedList);
GraphQL.newGraphQL(schema)
.instrumentation(chainedInstrumentation)
.build();
Apollo Tracing Instrumentation
graphql.execution.instrumentation.tracing.TracingInstrumentation是一种Instrumentation实现,用于创建有关正在执行的查询的跟踪信息。
它遵循在以下位置定义的Apollo建议的跟踪格式:https://github.com/apollographql/apollo-tracing https://github.com/apollographql/apollo-tracing_
将创建一个详细的跟踪视图,并将其放置在结果的扩展部分中。 有查询请求如下
{
human(id:"1001") {
id
name
}
}
返回详细信息,在extensions中有追踪信息
{
"data": {
"human": {
"id": "1001",
"name": "Darth Vader"
}
},
"extensions": {
"tracing": {
"version": 1,
"startTime": "2020-03-31T06:38:11.782Z",
"endTime": "2020-03-31T06:38:11.787Z",
"duration": 5009671,
"parsing": {
"startOffset": 763392,
"duration": 651573
},
"validation": {
"startOffset": 1075836,
"duration": 271042
},
"execution": {
"resolvers": [
{
"path": [
"human"
],
"parentType": "Query",
"returnType": "Human",
"fieldName": "human",
"startOffset": 1676625,
"duration": 803572
},
{
"path": [
"human",
"id"
],
"parentType": "Human",
"returnType": "ID!",
"fieldName": "id",
"startOffset": 3789805,
"duration": 752910
},
{
"path": [
"human",
"name"
],
"parentType": "Human",
"returnType": "String!",
"fieldName": "name",
"startOffset": 4693376,
"duration": 49369
}
]
}
},
"dataloader": {
"overall-statistics": {
"loadCount": 2,
"loadErrorCount": 0,
"loadErrorRatio": 0.0,
"batchInvokeCount": 2,
"batchLoadCount": 2,
"batchLoadRatio": 1.0,
"batchLoadExceptionCount": 0,
"batchLoadExceptionRatio": 0.0,
"cacheHitCount": 0,
"cacheHitRatio": 0.0
},
"individual-statistics": {
"characters": {
"loadCount": 2,
"loadErrorCount": 0,
"loadErrorRatio": 0.0,
"batchInvokeCount": 2,
"batchLoadCount": 2,
"batchLoadRatio": 1.0,
"batchLoadExceptionCount": 0,
"batchLoadExceptionRatio": 0.0,
"cacheHitCount": 0,
"cacheHitRatio": 0.0
}
}
}
}
}
Field Validation Instrumentation
graphql.execution.instrumentation.fieldvalidation.FieldValidationInstrumentation是一种工具实现,可用于在执行查询之前验证字段及其参数。如果在此过程中返回错误,则查询执行将中止,并且错误将出现在查询结果中。
您可以使自己实现FieldValidation,也可以使用SimpleFieldValidation类添加简单的每个字段检查规则。
/**
* @author 梦境迷离
* @version 1.0, 2020/3/31
*/
public class FieldValidationBuilder {
public static FieldValidationInstrumentation builder() {
//遇到是human的请求,强制验证id长度不能小于4
ExecutionPath fieldPath = ExecutionPath.parse("/human");
FieldValidation fieldValidation = new SimpleFieldValidation()
.addRule(fieldPath, (fieldAndArguments, environment) -> {
String nameArg = fieldAndArguments.getArgumentValue("id");
if (nameArg.length() < 4) {
return Optional.of(environment.mkError("Invalid id length", fieldAndArguments));
}
return Optional.empty();
});
return new FieldValidationInstrumentation(fieldValidation);
}
}
使用时只需要将FieldValidationBuilder放入ChainedInstrumentation中,如
Instrumentation instrumentation = new ChainedInstrumentation(asList(FieldValidationBuilder.builder(), new TracingInstrumentation(), new CustomInstrumentation()));
GraphQL graphQL = GraphQL.newGraphQL(graphQLSchema).instrumentation(instrumentation).build();
有查询如下
{
human(id:"1") { #改成长度不小4的字符串,就会返回数据或null
id
name
}
}
返回完整信息
{
"errors": [
{
"message": "Invalid id length",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"human"
]
}
]
}
完整例子请参考 https://github.com/jxnu-liguobin/springboot-examples
文档信息
- 本文作者:梦境迷离
- 本文链接:https://blog.dreamylost.cn/graphqljava/GraphqlJava-Instrumentation.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)