Apollo OpenTracing Plugin
raw JSON →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.
Common errors
error TypeError: Cannot read properties of undefined (reading 'startSpan') ↓
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. ↓
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: ... })]. Warnings
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. ↓
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. ↓
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. ↓
Install
npm install apollo-opentracing yarn add apollo-opentracing pnpm add apollo-opentracing Imports
- OpentracingPlugin wrong
import { OpentracingPlugin } from 'apollo-opentracing'; const OpentracingPlugin = require('apollo-opentracing');correctimport OpentracingPlugin from 'apollo-opentracing'; - Tracing Options wrong
const plugin = OpentracingPlugin({});correctimport OpentracingPlugin from 'apollo-opentracing'; const plugin = OpentracingPlugin({ server: yourServerTracer, local: yourLocalTracer, shouldTraceRequest: (requestContext) => true, shouldTraceFieldResolver: (source, args, context, info) => true });
Quickstart
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();