Apollo OpenTracing Plugin

raw JSON →
3.0.45 verified Sun Apr 19 auth: no javascript maintenance

apollo-opentracing is a plugin designed to integrate OpenTracing-compatible distributed tracing with Apollo Server. It enables automatic tracing of GraphQL requests and individual field resolvers, providing insights into query performance, and allows for selective tracing of requests and fields. The library helps in debugging by logging queries and results and supports span context propagation via HTTP headers, crucial for connecting traces across services. As of version 3.0.45, released in March 2023, the project primarily receives maintenance updates, focusing on dependency compatibility. A key differentiator is its adherence to the OpenTracing standard, allowing integration with various tracing backends like Jaeger and Zipkin. However, it's important to note that OpenTracing itself has been superseded by OpenTelemetry, making this library focused on a legacy tracing standard.

error TypeError: Cannot read properties of undefined (reading 'startSpan')
cause One or both of the required `server` or `local` OpenTracing `Tracer` instances were not provided or were `undefined` when initializing `OpentracingPlugin`.
fix
Ensure OpentracingPlugin is called with a configuration object containing server and local properties, each assigned a valid opentracing.Tracer instance: plugins: [OpentracingPlugin({ server: myServerTracer, local: myLocalTracer })].
error Error: Apollo Server plugin must be an object with an 'requestDidStart' method or a function that returns such an object.
cause This error typically occurs when integrating `apollo-opentracing` with Apollo Server v3+ but using the older plugin registration method or an incorrect import, or if the plugin factory isn't called.
fix
Ensure you are using import OpentracingPlugin from 'apollo-opentracing'; (ESM) or const OpentracingPlugin = require('apollo-opentracing').default; (CJS) and then correctly invoking it as a function within the plugins array: plugins: [OpentracingPlugin({ server: ..., local: ... })].
breaking The `apollo-opentracing` README examples show integration with `graphqlExpress` from `apollo-server-express`, which is part of Apollo Server v2 and earlier. However, the peer dependency is `apollo-server >=3.0.0`. Apollo Server v3+ requires a different setup using the `ApolloServer` class and its `plugins` array. The provided quickstart reflects the correct Apollo Server v3+ integration.
fix Migrate your Apollo Server setup to use the `ApolloServer` class and pass `OpentracingPlugin` within the `plugins` array in the constructor. Refer to Apollo Server v3+ documentation for correct initialization.
gotcha This library is built on OpenTracing, which has been officially deprecated since 2019 in favor of OpenTelemetry. While `apollo-opentracing` remains functional, new projects or those aiming for a future-proof observability stack should consider direct OpenTelemetry instrumentation for Apollo Server, which offers broader capabilities (metrics, logs, traces) and active development.
fix For new projects, consider using OpenTelemetry directly with an instrumentation library like `@opentelemetry/instrumentation-graphql` instead of `apollo-opentracing`. For existing projects, evaluate migration paths from OpenTracing to OpenTelemetry.
gotcha The `OpentracingPlugin` requires two distinct `Tracer` instances: `server` (for the root span) and `local` (for all other spans). Incorrect or missing initialization of these tracers will lead to runtime errors or silent failures in tracing.
fix Ensure you provide properly initialized instances of an `opentracing.Tracer` implementation (e.g., Jaeger, Zipkin, or a `MockTracer` for testing) for both the `server` and `local` options in the `OpentracingPlugin` constructor.
npm install apollo-opentracing
yarn add apollo-opentracing
pnpm add apollo-opentracing

This quickstart demonstrates setting up Apollo Server v3+ with `apollo-opentracing` using mock tracers. It initializes the Apollo Server with a basic schema and resolvers, then integrates the `OpentracingPlugin` to automatically trace requests and field resolutions. It also shows how to optionally control tracing and access the span within a resolver.

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { gql } from 'graphql-tag';
import OpentracingPlugin from 'apollo-opentracing';
import { MockTracer } from 'opentracing/lib/mock_tracer'; // Using a mock tracer for example

// Initialize OpenTracing tracers
const serverTracer = new MockTracer();
const localTracer = new MockTracer();

// Define your GraphQL schema
const typeDefs = gql`
  type Book {
    title: String
    author: String
  }

  type Query {
    books: [Book]
    hello: String
  }
`;

// Define your resolvers
const resolvers = {
  Query: {
    books: () => [
      { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
      { title: 'To Kill a Mockingbird', author: 'Harper Lee' },
    ],
    hello: (parent, args, context, info) => {
      // Access the current span from info.span if needed
      if (info.span) {
        info.span.log({ event: 'hello-resolver-executed' });
      }
      return 'Hello, GraphQL!';
    },
  },
};

async function startApolloServer() {
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [
      OpentracingPlugin({
        server: serverTracer,
        local: localTracer,
        // Optional: conditionally trace requests
        shouldTraceRequest: (requestContext) => {
          return requestContext.request.operationName !== 'IntrospectionQuery';
        },
        // Optional: conditionally trace field resolvers
        shouldTraceFieldResolver: (source, args, context, info) => {
          return info.fieldName !== '__typename';
        }
      }),
    ],
  });

  const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
  });

  console.log(`🚀 Server ready at ${url}`);
  console.log('Perform a GraphQL query (e.g., query { books { title } }) and check tracer logs.');

  // In a real application, you would export or periodically report spans from your tracer
  // For MockTracer, you can access finished spans directly:
  // console.log('Finished Spans:', serverTracer.finishedSpans());
}

startApolloServer();