当前位置: 代码迷 >> 综合 >> graphql-java(4)中如何做日志处理和追踪
  详细解决方案

graphql-java(4)中如何做日志处理和追踪

热度:67   发布时间:2023-09-23 10:21:38.0

https://dreamylost.cn/
文档 version = 1.4 仅供参考

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 {
    @Overridepublic InstrumentationState createState() {
    return new CustomInstrumentationState();}@Overridepublic InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExecutionParameters parameters) {
    long startNanos = System.nanoTime();return new SimpleInstrumentationContext<ExecutionResult>() {
    @Overridepublic void onCompleted(ExecutionResult result, Throwable t) {
    CustomInstrumentationState state = parameters.getInstrumentationState();state.recordTiming(parameters.getQuery(), System.nanoTime() - startNanos);}};}@Overridepublic DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters) {
    return dataFetcher;}@Overridepublic 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") {idname}
}

返回详细信息,在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长度不能小于4ExecutionPath 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的字符串,就会返回数据或nullidname}
}

返回完整信息

{
    "errors": [{
    "message": "Invalid id length","locations": [{
    "line": 2,"column": 3}],"path": ["human"]}]
}

完整例子请参考 https://github.com/jxnu-liguobin/springboot-examples

  相关解决方案