Instrumentation 包括系统默认及自定义两部分,如果是kickstart的boot实现,默认Instrumentation,可以参考GraphQLInstrumentationAutoConfiguration类,以下是这个类的代码:
@Configuration
@ConditionalOnClass(MetricsAutoConfiguration.class)
@AutoConfigureAfter({
MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,
GraphQLWebsocketAutoConfiguration.class})
@ConditionalOnProperty(value = "graphql.servlet.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties({
GraphQLServletProperties.class})
public class GraphQLInstrumentationAutoConfiguration {
@Value("${graphql.servlet.maxQueryComplexity:#{null}}")
private Integer maxQueryComplexity;
@Value("${graphql.servlet.maxQueryDepth:#{null}}")
private Integer maxQueryDepth;
@Value("${graphql.servlet.tracing-enabled:'false'}")
private String tracingEnabled;
@Bean
@ConditionalOnMissingBean({
TracingInstrumentation.class, MetricsInstrumentation.class})
@ConditionalOnExpression("${graphql.servlet.tracing-enabled:'false'}.equals('metrics-only')"
+ "|| ${graphql.servlet.tracing-enabled:'false'}.equals(true)")
public TracingInstrumentation tracingInstrumentation() {
return new TracingInstrumentation();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnExpression("${graphql.servlet.actuator-metrics:false}"
+ "&& ${graphql.servlet.tracing-enabled:'false'}.toString().equals('false')")
public TracingNoResolversInstrumentation tracingNoResolversInstrumentation() {
return new TracingNoResolversInstrumentation();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "graphql.servlet.max-query-complexity")
public MaxQueryComplexityInstrumentation maxQueryComplexityInstrumentation() {
return new MaxQueryComplexityInstrumentation(maxQueryComplexity);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "graphql.servlet.max-query-depth")
public MaxQueryDepthInstrumentation maxQueryDepthInstrumentation() {
return new MaxQueryDepthInstrumentation(maxQueryDepth);
}
@Bean
@ConditionalOnProperty(value = "graphql.servlet.actuator-metrics", havingValue = "true")
@ConditionalOnBean({
MeterRegistry.class, TracingInstrumentation.class})
@ConditionalOnMissingBean
public MetricsInstrumentation metricsInstrumentation(MeterRegistry meterRegistry) {
return new MetricsInstrumentation(meterRegistry, Boolean.TRUE.toString().equals(tracingEnabled));
}
@Bean
@ConditionalOnProperty(value = "graphql.servlet.actuator-metrics", havingValue = "true")
@ConditionalOnBean({
MeterRegistry.class, GraphQLWebsocketServlet.class})
@ConditionalOnMissingBean
public WebsocketMetrics websocketMetrics(MeterRegistry meterRegistry, GraphQLWebsocketServlet websocketServlet) {
return new WebsocketMetrics(meterRegistry, websocketServlet);
}
}
自定义一般包括extends SimpleInstrumentation及implements InstrumentationState
implements InstrumentationState的代码如下:
public class CustomInstrumentationState implements InstrumentationState {
private Map<String, Object> anyStateYouLike = new HashMap<>();
void recordTiming(String key, long time) {
anyStateYouLike.put(key, time);
}
}
extends SimpleInstrumentation代码如下
@Component
public class CustomInstrumentation extends SimpleInstrumentation {
@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 new SimpleInstrumentationContext<ExecutionResult>() {
@Override
public void onCompleted(ExecutionResult result, Throwable t) {
CustomInstrumentationState state = parameters.getInstrumentationState();
state.recordTiming(parameters.getQuery(), System.nanoTime() - startNanos);
System.out.println(parameters.getQuery() + ":" + (System.nanoTime() - startNanos));
}
};
}
@Override
public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
InstrumentationFieldFetchParameters parameters) {
//
// this allows you to intercept the data fetcher used to fetch a field and
// provide another one, perhaps
// that enforces certain behaviours or has certain side effects on the data
//
System.out.println("instrumentExecutionResult-beginFieldComplete:" + parameters.getField().toString());
GraphQLFieldDefinition field = parameters.getField();
System.out.println("GraphQLFieldDefinition...." + field.getName());
// SchemaDirectiveWiringEnvironment environment;
// DataFetcher originalDataFetcher =
// environment.getCodeRegistry().getDataFetcher(parentType, field);
// DataFetcher originalDataFetcher = field. field.getDataFetcher();
DataFetcher authDataFetcher = new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) throws Exception {
GraphQLType parentType = environment.getParentType();
//
// build a data fetcher that first checks authorisation roles before then
// calling the original data fetcher
//
// DataFetcher originalDataFetcher =
// environment.getCodeRegistry().getDataFetcher(parentType, field);
// TODO Auto-generated method stub
Object obj = dataFetcher.get(environment);
if (obj instanceof String) {
return "field:"+field.getName()+"be"+(String) obj + "masked";
}
return obj;
// return dataFetcher.get(environment);
}
};
// {
// @Override
// public Object get(DataFetchingEnvironment dataFetchingEnvironment) throws
// Exception {
// Map contextMap = dataFetchingEnvironment.getContext();
//
// Object obj = originalDataFetcher.get(dataFetchingEnvironment);
// if (obj instanceof String) {
// return (String)obj+"masked";
// }
// return obj;
// }
// };
field.transform(builder -> builder.dataFetcher(authDataFetcher));
return authDataFetcher;
}
@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
//
Map<String, Object> w = executionResult.toSpecification();
w.forEach((str, obj) -> {
System.out.println("instrumentExecutionResult-" + str);
System.out.println("instrumentExecutionResult-" + obj.toString());
if (obj instanceof String) {
}
});
System.out.println("instrumentExecutionResult-getOperation:" + parameters.getOperation());
System.out.println("instrumentExecutionResult-getQuery:" + parameters.getQuery());
return CompletableFuture.completedFuture(executionResult);
}
@Override
public InstrumentationContext<ExecutionResult> beginField(InstrumentationFieldParameters parameters) {
System.out.println("instrumentExecutionResult-beginField:" + parameters.getField().toString());
return new SimpleInstrumentationContext<>();
}
@Override
public InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters) {
System.out.println("instrumentExecutionResult-beginFieldFetch:" + parameters.getField().toString());
return new SimpleInstrumentationContext<>();
}
@Override
public InstrumentationContext<ExecutionResult> beginFieldComplete(
InstrumentationFieldCompleteParameters parameters) {
//
// now change the field definition to have the new authorising data fetcher
System.out.println("GraphQLFieldDefinition...." + parameters.getFetchedValue().toString());
System.out.println("GraphQLFieldDefinition...." + parameters.getFetchedValue().toString());
return new SimpleInstrumentationContext<>();
}
@Override
public InstrumentationContext<ExecutionResult> beginFieldListComplete(
InstrumentationFieldCompleteParameters parameters) {
System.out.println("instrumentExecutionResult-beginFieldListComplete:" + parameters.getField().toString());
return new SimpleInstrumentationContext<>();
}
}
上面的代码是一个修改输出的简单示意。