Metrics

Metrics are captured during execution if ExecutionOptions.EnableMetrics property is set to true. By default, metrics collection is disabled to improve performance.

Enabling metrics can help you determine performance issues within a resolver or validation. Field metrics are captured using Field Middleware and the results are returned as a PerfRecord array on the ExecutionResult. You can then generate Apollo Tracing data with the EnrichWithApolloTracing() extension method.

var start = DateTime.UtcNow;

var executor = new DocumentExecutor();
ExecutionResult result = executor.ExecuteAsync(_ =>
{
  _.Schema = schema;
  _.Query = "...";
  _.EnableMetrics = true;
  _.FieldMiddleware.Use<InstrumentFieldsMiddleware>();
});

result.EnrichWithApolloTracing(start);

Alternatively, you can use the AddApolloTracing extension method to append the tracing results to the execution; this is ideal when wiring up GraphQL via dependency injection.

services.AddGraphQL(b => b
    .AddSchema<StarWarsSchema>()
    .AddApolloTracing()
    .AddSystemTextJson());

Also you could create a listener that hooks in after the execution and uses the Apollo tracing data to synthesize some other traces, for example, for Application Insights.

Conditionally enable metrics by HTTP header

If you want to enable metrics for just some HTTP requests then you may provide a special tracing HTTP header and configure GraphQL execution engine to check the presence of that header.

public static class GraphQLBuilderMetricsExtensions
{
    public static IGraphQLBuilder EnableMetricsByHeader(this IGraphQLBuilder builder, string headerName = "X-GRAPHQL-METRICS")
    {
        return builder.ConfigureExecution(async (options, next) =>
        {
            if (!options.EnableMetrics)
            {
                var accessor = options.RequestServices.GetRequiredService<IHttpContextAccessor>();
                options.EnableMetrics = accessor.HttpContext.Request.Headers.ContainsKey(headerName);
            }
            return await next(options).ConfigureAwait(false);
        });
    }
}

services.AddGraphQL(b => b
    .AddSchema<StarWarsSchema>()
    .EnableMetricsByHeader()
    .AddSystemTextJson());

Metrics data example

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke"
        },
        {
          "name": "C-3PO"
        }
      ]
    }
  },
  "extensions": {
    "tracing": {
      "version": 1,
      "startTime": "2018-07-28T21:39:27.160902Z",
      "endTime": "2018-07-28T21:39:27.372902Z",
      "duration": 212304000,
      "parsing": {
        "startOffset": 57436000,
        "duration": 21985999
      },
      "validation": {
        "startOffset": 57436000,
        "duration": 21985999
      },
      "execution": {
        "resolvers": [
          {
            "path": [
              "hero"
            ],
            "parentType": "Query",
            "fieldName": "hero",
            "returnType": "Character",
            "startOffset": 147389000,
            "duration": 2756000
          },
          {
            "path": [
              "hero",
              "name"
            ],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": 208043000,
            "duration": 396000
          },
          {
            "path": [
              "hero",
              "friends"
            ],
            "parentType": "Droid",
            "fieldName": "friends",
            "returnType": "[Character]",
            "startOffset": 208533000,
            "duration": 1067999
          },
          {
            "path": [
              "hero",
              "friends",
              0,
              "name"
            ],
            "parentType": "Human",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": 210501000,
            "duration": 33999
          },
          {
            "path": [
              "hero",
              "friends",
              1,
              "name"
            ],
            "parentType": "Droid",
            "fieldName": "name",
            "returnType": "String",
            "startOffset": 210542000,
            "duration": 3000
          }
        ]
      }
    }
  }
}