UNPKG

@envelop/apollo-tracing

Version:

This plugin tracks execution and resolvers and reports it using [`apollo-tracing`](https://github.com/apollographql/apollo-server/tree/main/packages/apollo-tracing) format (based on GraphQL `extensions`).

80 lines (79 loc) 3.36 kB
import { responsePathAsArray } from 'graphql'; import { handleStreamOrSingleExecutionResult } from '@envelop/core'; import { useOnResolve } from '@envelop/on-resolve'; const HR_TO_NS = 1e9; const NS_TO_MS = 1e6; function durationHrTimeToNanos(hrtime) { return hrtime[0] * HR_TO_NS + hrtime[1]; } const deltaFrom = (hrtime) => { const delta = process.hrtime(hrtime); const ns = delta[0] * HR_TO_NS + delta[1]; return { ns, get ms() { return ns / NS_TO_MS; }, }; }; const apolloTracingSymbol = Symbol('apolloTracing'); export const useApolloTracing = () => { return { onPluginInit({ addPlugin }) { addPlugin(useOnResolve(({ info, context }) => { const ctx = context[apolloTracingSymbol]; // Taken from https://github.com/apollographql/apollo-server/blob/main/packages/apollo-tracing/src/index.ts const resolverCall = { path: info.path, fieldName: info.fieldName, parentType: info.parentType, returnType: info.returnType, startOffset: process.hrtime(ctx.hrtime), }; return () => { resolverCall.endOffset = process.hrtime(ctx.hrtime); ctx.resolversTiming.push(resolverCall); }; })); }, onExecute(onExecuteContext) { const ctx = { startTime: new Date(), resolversTiming: [], hrtime: process.hrtime(), }; onExecuteContext.extendContext({ [apolloTracingSymbol]: ctx }); return { onExecuteDone(payload) { const endTime = new Date(); const tracing = { version: 1, startTime: ctx.startTime.toISOString(), endTime: endTime.toISOString(), duration: deltaFrom(ctx.hrtime).ns, execution: { resolvers: ctx.resolversTiming.map(resolverCall => { const startOffset = durationHrTimeToNanos(resolverCall.startOffset); const duration = resolverCall.endOffset ? durationHrTimeToNanos(resolverCall.endOffset) - startOffset : 0; return { path: [...responsePathAsArray(resolverCall.path)], parentType: resolverCall.parentType.toString(), fieldName: resolverCall.fieldName, returnType: resolverCall.returnType.toString(), startOffset, duration, }; }), }, }; return handleStreamOrSingleExecutionResult(payload, ({ result }) => { result.extensions = result.extensions || {}; result.extensions.tracing = tracing; }); }, }; }, }; };