-
-
Save jgcmarins/4aaea1e05ccd51e17078f75d83b70c9f to your computer and use it in GitHub Desktop.
traceResolver higher order function to wrap your GraphQL Resolvers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| version: 1, | |
| startTime: '2020-03-31T15:25:05.747Z', | |
| endTime: '2020-03-31T15:25:05.747Z', | |
| duration: 3130, | |
| execution: { | |
| resolvers: [ | |
| { | |
| path: [ 'posts', 'analytics', 'quantity' ], | |
| parentType: 'User', | |
| fieldName: 'finalScore', | |
| returnType: 'Float', | |
| startOffset: 11169, | |
| duration: 15702457072, | |
| durationMilli: 15702.457072, | |
| durationSeconds: 15.702457072 | |
| } | |
| ] | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { ResponsePath, responsePathAsArray, GraphQLType } from 'graphql'; | |
| import util from 'util'; | |
| export const debug = (obj: object) => { | |
| // eslint-disable-next-line | |
| console.log(util.inspect(obj, false, null, true)); | |
| }; | |
| // based on apollo-tracing | |
| // https://github.com/apollographql/apollo-server/blob/master/packages/apollo-tracing/src/index.ts | |
| type HighResolutionTime = [number, number]; | |
| // Converts an hrtime array (as returned from process.hrtime) to nanoseconds. | |
| // | |
| // ONLY CALL THIS ON VALUES REPRESENTING DELTAS, NOT ON THE RAW RETURN VALUE | |
| // FROM process.hrtime() WITH NO ARGUMENTS. | |
| // | |
| // The entire point of the hrtime data structure is that the JavaScript Number | |
| // type can't represent all int64 values without loss of precision: | |
| // Number.MAX_SAFE_INTEGER nanoseconds is about 104 days. Calling this function | |
| // on a duration that represents a value less than 104 days is fine. Calling | |
| // this function on an absolute time (which is generally roughly time since | |
| // system boot) is not a good idea. | |
| const durationHrTimeToNanos = (hrtime: HighResolutionTime) => hrtime[0] * 1e9 + hrtime[1]; | |
| const formatTracing = ({ startWallTime, endWallTime, duration, resolverCalls }) => ({ | |
| version: 1, | |
| startTime: startWallTime.toISOString(), | |
| endTime: endWallTime.toISOString(), | |
| duration: durationHrTimeToNanos(duration), | |
| execution: { | |
| resolvers: resolverCalls.map(resolverCall => { | |
| const startOffset = durationHrTimeToNanos(resolverCall.startOffset); | |
| const durationNano = 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: durationNano, | |
| durationMilli: durationNano / 1e6, | |
| durationSeconds: durationNano / 1e9, | |
| }; | |
| }), | |
| }, | |
| }); | |
| type ResolverCall = { | |
| path: ResponsePath; | |
| fieldName: string; | |
| parentType: GraphQLType; | |
| returnType: GraphQLType; | |
| startOffset: HighResolutionTime; | |
| endOffset?: HighResolutionTime; | |
| }; | |
| export const traceResolver = resolver => async (source, args, context, info) => { | |
| // requestDidStart | |
| const startWallTime = new Date(); | |
| const startHrTime = process.hrtime(); | |
| // executionDidStart | |
| const duration = process.hrtime(startHrTime); | |
| const endWallTime = new Date(); | |
| const resolverCall: ResolverCall = { | |
| path: info.path, | |
| fieldName: info.fieldName, | |
| parentType: info.parentType, | |
| returnType: info.returnType, | |
| startOffset: process.hrtime(startHrTime), | |
| }; | |
| // willResolveField | |
| const result = await resolver(source, args, context, info); | |
| resolverCall.endOffset = process.hrtime(startHrTime); | |
| debug( | |
| formatTracing({ | |
| startWallTime, | |
| endWallTime, | |
| duration, | |
| resolverCalls: [resolverCall], | |
| }), | |
| ); | |
| return result; | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| resolve: traceResolver(resolver), |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment