apollo-server/docs/source/features/metrics.md
Jesse Rosenberger 9b8dc1b607
Address unaddressed feedback from #1223.
These were things I'd suggested prior to merging and I just happened to come across it again, only to find they were still outstanding:

https://github.com/apollographql/apollo-server/pull/1223
2019-01-08 20:25:18 +02:00

5.3 KiB

title description
Monitoring and metrics How to monitor Apollo Server's performance

Understanding the behavior of GraphQL execution inside of Apollo Server is critical to developing and running a production GraphQL layer. Apollo Server enables GraphQL monitoring in Apollo Engine and provides more primitive native mechanisms to log each phase of a GraphQL request.

Apollo Engine

Apollo Engine provides an integrated hub for all GraphQL performance data that is free for one million queries per month. With an API key from the Engine UI, Apollo Server reports performance and error data out-of-band. Apollo Engine then aggregates and displays information for queries, requests, the schema, and errors. By leveraging this data, Apollo Engine offers alerts via Slack and Datadog integrations.

To set up Apollo Server with Engine, click here to get an Engine API key. This API key can be passed directly to the Apollo Server constructor.

const { ApolloServer } = require("apollo-server");

const server = new ApolloServer({
  typeDefs,
  resolvers,
  engine: {
    apiKey: "YOUR API KEY HERE"
  }
});

server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

The API key can also be set with the ENGINE_API_KEY environment variable. Setting an environment variable can be done in commandline as seen below or with the dotenv npm package.

# Replace YOUR_API_KEY with the API key provided within Apollo Engine.
ENGINE_API_KEY=YOUR_API_KEY node start-server.js

Client awareness

Apollo Engine accepts metrics annotated with client information. The Engine UI is then able to filter metrics and usage patterns by these names and versions. To provide metrics to the Engine, pass a generateClientInfo function into the ApolloServer constructor, like so:

const { ApolloServer } = require("apollo-server");

const server = new ApolloServer({
  typeDefs,
  resolvers,
  engine: {
    apiKey: "YOUR API KEY HERE",
    generateClientInfo: ({
      request
    }) => {
      const headers = request.http & request.http.headers;
      if(headers) {
        return {
          clientName: headers['apollo-client-name'],
          clientVersion: headers['apollo-client-version'],
        };
      } else {
        return {
          clientName: "Unknown Client",
          clientVersion: "Unversioned",
        };
      }
    },
  }
});

server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

Note: the default implementation looks at clientInfo field in the extensions of the GraphQL request

Logging

Apollo Server provides two ways to log a server: per input, response, and errors or periodically throughout a request's lifecycle. Treating the GraphQL execution as a black box by logging the inputs and outputs of the system allows developers to diagnose issues quickly without being mired by lower level logs. Once a problem has been found at a high level, the lower level logs enable accurate tracing of how a request was handled.

High-level logging

Apollo Server allows formatError and formatResponse configuration options which can be defined as callback-functions which receive error or response arguments respectively.

For the sake of simplicity, these examples use console.log to output error and debugging information though a more complete example might utilize existing logging or error-reporting facilities.

const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: error => {
    console.log(error);
    return error;
  },
  formatResponse: response => {
    console.log(response);
    return response;
  },
});

server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

Granular logs

For more advanced cases, Apollo Server provides an experimental api that accepts an array of graphql-extensions to the extensions field. These extensions receive a variety of lifecycle calls for each phase of a GraphQL request and can keep state, such as the request headers.

const { ApolloServer }  = require('apollo-server');
const LoggingExtension = require('./logging');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  extensions: [() => new LoggingExtension()]
});

server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

For example the logFunction from Apollo Server 1 can be implemented as an extension and could be modified to add additional state or functionality. The example uses a beta of graphql-extensions, which can be added to a project with npm install graphql-extensions@beta.