UNPKG

2.42 kBPlain TextView Raw
1import {
2 responsePathAsArray,
3 GraphQLResolveInfo,
4 GraphQLFieldResolver
5} from "graphql";
6
7type HighResolutionTime = [number, number];
8
9const traceHRStartTime = Symbol("HR Start Time");
10const traceWallStartTime = Symbol("Wall Start Time");
11export const apolloTracingContext = Symbol("Apollo Tracing Context");
12
13export interface ApolloTracingContext {
14 [traceHRStartTime]: HighResolutionTime;
15 [traceWallStartTime]: Date;
16 version: 1;
17 startTime: string;
18 endTime: string;
19 duration: number;
20 execution: {
21 parsing?: {
22 startOffset: number;
23 duration: number;
24 };
25 validation?: {
26 startOffset: number;
27 duration: number;
28 };
29 resolvers: ApolloTracingResolverStats[];
30 };
31}
32
33export interface ApolloTracingResolverStats {
34 path: (string | number)[];
35 parentType: string;
36 fieldName: string;
37 returnType: string;
38 startOffset: number;
39 duration: number;
40}
41
42function durationHrTimeToNanos(hrtime: HighResolutionTime): number {
43 return hrtime[0] * 1e9 + hrtime[1];
44}
45
46export async function apolloTracingGraphQLMiddleware(
47 resolve: GraphQLFieldResolver<any, any, any>,
48 parent: unknown,
49 args: unknown,
50 context: { [apolloTracingContext]: ApolloTracingContext },
51 info: GraphQLResolveInfo
52): Promise<any> {
53 const startOffset = durationHrTimeToNanos(
54 process.hrtime(context[apolloTracingContext][traceHRStartTime])
55 );
56 try {
57 return await resolve(parent, args, context, info);
58 } finally {
59 context[apolloTracingContext].execution.resolvers.push({
60 path: [...responsePathAsArray(info.path)],
61 parentType: info.parentType.toString(),
62 fieldName: info.fieldName,
63 returnType: info.returnType.toString(),
64 startOffset,
65 duration:
66 durationHrTimeToNanos(
67 process.hrtime(context[apolloTracingContext][traceHRStartTime])
68 ) - startOffset
69 });
70 }
71}
72
73export function startTracingContext(): ApolloTracingContext {
74 const wallStartTime = new Date();
75 return {
76 [traceHRStartTime]: process.hrtime(),
77 [traceWallStartTime]: wallStartTime,
78 version: 1,
79 startTime: wallStartTime.toISOString(),
80 endTime: "",
81 duration: 0,
82 execution: {
83 resolvers: []
84 }
85 };
86}
87
88export function endTracingContext(context: ApolloTracingContext): void {
89 context.endTime = new Date().toISOString();
90 context.duration = durationHrTimeToNanos(
91 process.hrtime(context[traceHRStartTime])
92 );
93}