From 6009d8a00278e5d56377887b6a7c0aa902ef2391 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Mon, 30 Mar 2020 15:02:44 +0300 Subject: [PATCH 1/8] refactor: Introduce "tracing" plugin and switch request pipeline to use it. This commit introduces a `plugin` (named) export from the `apollo-tracing` package, which uses the new "plugin" hooks rather than the previous implementation (exported as `TracingExtension`) which uses the soon-to-be-deprecated "extensions" hooks. The functionality is intended to be identical, in spirit. Since the delta of the commits was otherwise confusing, I've left the `TracingExtension` present and exported and will remove it in a subsequent commit. Briefly summarizing what the necessary changes were: 1. We no longer use a class instance to house the extension, which was necessitated by the `graphql-extensions` API. This means that uses of `this` have been replaced with function scoped variables by the same name. 2. The logic which actually does the formatting (previously handled by the `format` method in `graphql-extension`, now takes place within the plugin API's `willSendResponse` method. --- package-lock.json | 1 + .../apollo-server-core/src/ApolloServer.ts | 9 +- .../apollo-server-core/src/requestPipeline.ts | 6 -- packages/apollo-tracing/package.json | 1 + packages/apollo-tracing/src/index.ts | 93 ++++++++++++++++++- packages/apollo-tracing/tsconfig.json | 1 + 6 files changed, 101 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 20a701000e3..31bec050eb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4652,6 +4652,7 @@ "version": "file:packages/apollo-tracing", "requires": { "apollo-server-env": "file:packages/apollo-server-env", + "apollo-server-plugin-base": "file:packages/apollo-server-plugin-base", "graphql-extensions": "file:packages/graphql-extensions" } }, diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 5b94b5ea022..73df1ba5673 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -70,6 +70,7 @@ import { import { Headers } from 'apollo-server-env'; import { buildServiceDefinition } from '@apollographql/apollo-tools'; import { Logger } from "apollo-server-types"; +import { plugin as pluginTracing } from "apollo-tracing"; const NoIntrospection = (context: ValidationContext) => ({ Field(node: FieldDefinitionNode) { @@ -783,11 +784,13 @@ export class ApolloServerBase { } private ensurePluginInstantiation(plugins?: PluginDefinition[]): void { - if (!plugins || !plugins.length) { - return; + const pluginsToInit = [...plugins || []]; + + if (this.config.tracing) { + pluginsToInit.push(pluginTracing()) } - this.plugins = plugins.map(plugin => { + this.plugins = pluginsToInit.map(plugin => { if (typeof plugin === 'function') { return plugin(); } diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 6393d82c95a..34ce061a5e1 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -26,7 +26,6 @@ import { CacheControlExtension, CacheControlExtensionOptions, } from 'apollo-cache-control'; -import { TracingExtension } from 'apollo-tracing'; import { ApolloError, fromGraphQLError, @@ -95,7 +94,6 @@ export interface GraphQLRequestPipelineConfig { dataSources?: () => DataSources; extensions?: Array<() => GraphQLExtension>; - tracing?: boolean; persistedQueries?: PersistedQueryOptions; cacheControl?: CacheControlExtensionOptions; @@ -600,10 +598,6 @@ export async function processGraphQLRequest( // objects. const extensions = config.extensions ? config.extensions.map(f => f()) : []; - if (config.tracing) { - extensions.push(new TracingExtension()); - } - if (config.cacheControl) { cacheControlExtension = new CacheControlExtension(config.cacheControl); extensions.push(cacheControlExtension); diff --git a/packages/apollo-tracing/package.json b/packages/apollo-tracing/package.json index 6fe6e4434d9..316cc83aa61 100644 --- a/packages/apollo-tracing/package.json +++ b/packages/apollo-tracing/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "apollo-server-env": "file:../apollo-server-env", + "apollo-server-plugin-base": "file:../apollo-server-plugin-base", "graphql-extensions": "file:../graphql-extensions" }, "peerDependencies": { diff --git a/packages/apollo-tracing/src/index.ts b/packages/apollo-tracing/src/index.ts index 9c31c22ed54..fee8e9792f5 100644 --- a/packages/apollo-tracing/src/index.ts +++ b/packages/apollo-tracing/src/index.ts @@ -4,7 +4,7 @@ import { GraphQLResolveInfo, GraphQLType, } from 'graphql'; - +import { ApolloServerPlugin } from "apollo-server-plugin-base"; import { GraphQLExtension } from 'graphql-extensions'; export interface TracingFormat { @@ -33,6 +33,97 @@ interface ResolverCall { endOffset?: HighResolutionTime; } +export const plugin = (_futureOptions = {}) => (): ApolloServerPlugin => ({ + requestDidStart() { + let startWallTime: Date | undefined; + let endWallTime: Date | undefined; + let startHrTime: HighResolutionTime | undefined; + let duration: HighResolutionTime | undefined; + const resolverCalls: ResolverCall[] = []; + + startWallTime = new Date(); + startHrTime = process.hrtime(); + + return { + executionDidStart() { + // It's a little odd that we record the end time after execution rather + // than at the end of the whole request, but because we need to include + // our formatted trace in the request itself, we have to record it + // before the request is over! It's also odd that we don't do traces for + // parse or validation errors, but runQuery doesn't currently support + // that, as format() is only invoked after execution. + return () => { + duration = process.hrtime(startHrTime); + endWallTime = new Date(); + }; + }, + willResolveField(...args) { + const [, , , info] = args; + + const resolverCall: ResolverCall = { + path: info.path, + fieldName: info.fieldName, + parentType: info.parentType, + returnType: info.returnType, + startOffset: process.hrtime(startHrTime), + }; + + resolverCalls.push(resolverCall); + + return () => { + resolverCall.endOffset = process.hrtime(startHrTime); + }; + }, + willSendResponse({ response }) { + // In the event that we are called prior to the initialization of + // critical date metrics, we'll return undefined to signal that the + // extension did not format properly. Any undefined extension + // results are simply purged by the graphql-extensions module. + if ( + typeof startWallTime === 'undefined' || + typeof endWallTime === 'undefined' || + typeof duration === 'undefined' + ) { + return; + } + + const extensions = + response.extensions || (response.extensions = Object.create(null)); + + if (typeof extensions.tracing !== 'undefined') { + throw new Error("The tracing information already existed."); + } + + // Set the extensions. + extensions.tracing = { + version: 1, + startTime: startWallTime.toISOString(), + endTime: endWallTime.toISOString(), + duration: durationHrTimeToNanos(duration), + execution: { + resolvers: resolverCalls.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, + }; + }), + }, + }; + }, + }; + }, +}) + export class TracingExtension implements GraphQLExtension { private startWallTime?: Date; diff --git a/packages/apollo-tracing/tsconfig.json b/packages/apollo-tracing/tsconfig.json index 0de28001c29..1276353ea04 100644 --- a/packages/apollo-tracing/tsconfig.json +++ b/packages/apollo-tracing/tsconfig.json @@ -8,5 +8,6 @@ "exclude": ["**/__tests__", "**/__mocks__"], "references": [ { "path": "../graphql-extensions" }, + { "path": "../apollo-server-plugin-base" }, ] } From 8ec39c98ffbeb4c695a72a24ec1fc768545be2c8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Mon, 30 Mar 2020 15:58:06 +0300 Subject: [PATCH 2/8] eliminate!: Remove deprecated `TracingExtension`. This follows-up 672fa0953 and removes the no-longer used/necessary `TracingExtension` extension which uses the soon-to-be-deprecated `graphql-extensions` API, now that it has been replaced with an implementation that uses the plugin API. --- package-lock.json | 3 +- packages/apollo-tracing/package.json | 3 +- packages/apollo-tracing/src/index.ts | 91 --------------------------- packages/apollo-tracing/tsconfig.json | 1 - 4 files changed, 2 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31bec050eb2..9264f6152ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4652,8 +4652,7 @@ "version": "file:packages/apollo-tracing", "requires": { "apollo-server-env": "file:packages/apollo-server-env", - "apollo-server-plugin-base": "file:packages/apollo-server-plugin-base", - "graphql-extensions": "file:packages/graphql-extensions" + "apollo-server-plugin-base": "file:packages/apollo-server-plugin-base" } }, "apollo-utilities": { diff --git a/packages/apollo-tracing/package.json b/packages/apollo-tracing/package.json index 316cc83aa61..99a169b435c 100644 --- a/packages/apollo-tracing/package.json +++ b/packages/apollo-tracing/package.json @@ -12,8 +12,7 @@ }, "dependencies": { "apollo-server-env": "file:../apollo-server-env", - "apollo-server-plugin-base": "file:../apollo-server-plugin-base", - "graphql-extensions": "file:../graphql-extensions" + "apollo-server-plugin-base": "file:../apollo-server-plugin-base" }, "peerDependencies": { "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" diff --git a/packages/apollo-tracing/src/index.ts b/packages/apollo-tracing/src/index.ts index fee8e9792f5..31ba20a6f18 100644 --- a/packages/apollo-tracing/src/index.ts +++ b/packages/apollo-tracing/src/index.ts @@ -1,11 +1,9 @@ import { ResponsePath, responsePathAsArray, - GraphQLResolveInfo, GraphQLType, } from 'graphql'; import { ApolloServerPlugin } from "apollo-server-plugin-base"; -import { GraphQLExtension } from 'graphql-extensions'; export interface TracingFormat { version: 1; @@ -124,95 +122,6 @@ export const plugin = (_futureOptions = {}) => (): ApolloServerPlugin => ({ }, }) -export class TracingExtension - implements GraphQLExtension { - private startWallTime?: Date; - private endWallTime?: Date; - private startHrTime?: HighResolutionTime; - private duration?: HighResolutionTime; - - private resolverCalls: ResolverCall[] = []; - - public requestDidStart() { - this.startWallTime = new Date(); - this.startHrTime = process.hrtime(); - } - - public executionDidStart() { - // It's a little odd that we record the end time after execution rather than - // at the end of the whole request, but because we need to include our - // formatted trace in the request itself, we have to record it before the - // request is over! It's also odd that we don't do traces for parse or - // validation errors, but runQuery doesn't currently support that, as - // format() is only invoked after execution. - return () => { - this.duration = process.hrtime(this.startHrTime); - this.endWallTime = new Date(); - }; - } - - public willResolveField( - _source: any, - _args: { [argName: string]: any }, - _context: TContext, - info: GraphQLResolveInfo, - ) { - const resolverCall: ResolverCall = { - path: info.path, - fieldName: info.fieldName, - parentType: info.parentType, - returnType: info.returnType, - startOffset: process.hrtime(this.startHrTime), - }; - - this.resolverCalls.push(resolverCall); - - return () => { - resolverCall.endOffset = process.hrtime(this.startHrTime); - }; - } - - public format(): [string, TracingFormat] | undefined { - // In the event that we are called prior to the initialization of critical - // date metrics, we'll return undefined to signal that the extension did not - // format properly. Any undefined extension results are simply purged by - // the graphql-extensions module. - if ( - typeof this.startWallTime === 'undefined' || - typeof this.endWallTime === 'undefined' || - typeof this.duration === 'undefined' - ) { - return; - } - - return [ - 'tracing', - { - version: 1, - startTime: this.startWallTime.toISOString(), - endTime: this.endWallTime.toISOString(), - duration: durationHrTimeToNanos(this.duration), - execution: { - resolvers: this.resolverCalls.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, - }; - }), - }, - }, - ]; - } -} - type HighResolutionTime = [number, number]; // Converts an hrtime array (as returned from process.hrtime) to nanoseconds. diff --git a/packages/apollo-tracing/tsconfig.json b/packages/apollo-tracing/tsconfig.json index 1276353ea04..29dff935854 100644 --- a/packages/apollo-tracing/tsconfig.json +++ b/packages/apollo-tracing/tsconfig.json @@ -7,7 +7,6 @@ "include": ["src/**/*"], "exclude": ["**/__tests__", "**/__mocks__"], "references": [ - { "path": "../graphql-extensions" }, { "path": "../apollo-server-plugin-base" }, ] } From 7e4cc4b7d99aeaffe6a27b2cf97b98d7713c2a5c Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Thu, 16 Apr 2020 13:55:16 +0300 Subject: [PATCH 3/8] Clear up error message in defense mechanism against existing `tracing`. This package should never have already set it itself prior to this point, but the circumstance exists that something (anything) else could have already used the `extensions` sink to attach a value. This guards against that. --- packages/apollo-tracing/src/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/apollo-tracing/src/index.ts b/packages/apollo-tracing/src/index.ts index 31ba20a6f18..b5cb8ec5cc3 100644 --- a/packages/apollo-tracing/src/index.ts +++ b/packages/apollo-tracing/src/index.ts @@ -5,6 +5,8 @@ import { } from 'graphql'; import { ApolloServerPlugin } from "apollo-server-plugin-base"; +const { PACKAGE_NAME } = require("../package.json").name; + export interface TracingFormat { version: 1; startTime: string; @@ -88,8 +90,11 @@ export const plugin = (_futureOptions = {}) => (): ApolloServerPlugin => ({ const extensions = response.extensions || (response.extensions = Object.create(null)); + // Be defensive and make sure nothing else (other plugin, etc.) has + // already used the `tracing` property on `extensions`. if (typeof extensions.tracing !== 'undefined') { - throw new Error("The tracing information already existed."); + throw new Error(PACKAGE_NAME + ": Could not add `tracing` to " + + "`extensions` since `tracing` was unexpectedly already present."); } // Set the extensions. From fecea35b7cceaf6aaa1181bea32b34929b649b2b Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Thu, 16 Apr 2020 15:34:45 +0300 Subject: [PATCH 4/8] Update README.md for `apollo-tracing`. --- packages/apollo-tracing/README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/apollo-tracing/README.md b/packages/apollo-tracing/README.md index ffaab016414..f23149a579a 100644 --- a/packages/apollo-tracing/README.md +++ b/packages/apollo-tracing/README.md @@ -12,14 +12,13 @@ This data can be consumed by [Apollo Graph Manager](https://www.apollographql.co Apollo Server includes built-in support for tracing from version 1.1.0 onwards. -The only code change required is to add `tracing: true` to the options passed to the Apollo Server middleware function for your framework of choice. For example, for Express: +The only code change required is to add `tracing: true` to the options passed to the `ApolloServer` constructor options for your integration of choice. For example, for [`apollo-server-express`](https://npm.im/apollo-server-express): ```javascript -app.use('/graphql', bodyParser.json(), graphqlExpress({ +const { ApolloServer } = require('apollo-server-express'); + +const server = new ApolloServer({ schema, - context: {}, tracing: true, -})); +}); ``` - -> If you are using `express-graphql`, we recommend you switch to Apollo Server. Both `express-graphql` and Apollo Server are based on the [`graphql-js`](https://github.com/graphql/graphql-js) reference implementation, and switching should only require changing a few lines of code. From 3e9188fb81ad7a103cdb17a6707a29275866c464 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Thu, 16 Apr 2020 15:36:48 +0300 Subject: [PATCH 5/8] Add CHANGELOG.md for #3991. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f6db09c1a6..a32e400dd26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The version headers in this history reflect the versions of Apollo Server itself > The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the the appropriate changes within that release will be moved into the new section. - `apollo-server-lambda`: Support file uploads on AWS Lambda [Issue #1419](https://github.com/apollographql/apollo-server/issues/1419) [Issue #1703](https://github.com/apollographql/apollo-server/issues/1703) [PR #3926](https://github.com/apollographql/apollo-server/pull/3926) +- `apollo-tracing`: This package's internal integration with Apollo Server has been switched from using the soon-to-be-deprecated`graphql-extensions` API to using [the request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/). Behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991) - **breaking** `apollo-engine-reporting-protobuf`: Drop legacy fields that were never used by `apollo-engine-reporting`. Added new fields `StatsContext` to allow `apollo-server` to send summary stats instead of full traces, and renamed `FullTracesReport` to `Report` and `Traces` to `TracesAndStats` since reports now can include stats as well as traces. ### v2.12.0 From 98bae446d37704939bd7e0bf010503c66215dfd8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 28 Apr 2020 15:53:57 +0300 Subject: [PATCH 6/8] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a32e400dd26..361931c8bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ The version headers in this history reflect the versions of Apollo Server itself > The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the the appropriate changes within that release will be moved into the new section. - `apollo-server-lambda`: Support file uploads on AWS Lambda [Issue #1419](https://github.com/apollographql/apollo-server/issues/1419) [Issue #1703](https://github.com/apollographql/apollo-server/issues/1703) [PR #3926](https://github.com/apollographql/apollo-server/pull/3926) -- `apollo-tracing`: This package's internal integration with Apollo Server has been switched from using the soon-to-be-deprecated`graphql-extensions` API to using [the request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/). Behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991) +- `apollo-tracing`: This package is considered deprecated and — along with its `tracing: Boolean` configuration option on the `ApolloServer` constructor options — will cease to exist in Apollo Server 3.x. Until that occurs, we've updated the _internal_ integration of this package with Apollo Server itself to use the newer [request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/), rather than the _also_ soon-to-be-deprecated-`graphql-extensions` API it previously leveraged. The behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991) - **breaking** `apollo-engine-reporting-protobuf`: Drop legacy fields that were never used by `apollo-engine-reporting`. Added new fields `StatsContext` to allow `apollo-server` to send summary stats instead of full traces, and renamed `FullTracesReport` to `Report` and `Traces` to `TracesAndStats` since reports now can include stats as well as traces. ### v2.12.0 From ef4ed58cb5e14bb638e4580760673de347a88de0 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Thu, 7 May 2020 09:06:38 +0000 Subject: [PATCH 7/8] Revert "Update CHANGELOG.md" This reverts the public messaging about `tracing` deprecation in commit 98bae446d37704939bd7e0bf010503c66215dfd8, for now, until we can discuss its fate a bit more, and how we intend on making up for that. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 361931c8bef..a32e400dd26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ The version headers in this history reflect the versions of Apollo Server itself > The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the the appropriate changes within that release will be moved into the new section. - `apollo-server-lambda`: Support file uploads on AWS Lambda [Issue #1419](https://github.com/apollographql/apollo-server/issues/1419) [Issue #1703](https://github.com/apollographql/apollo-server/issues/1703) [PR #3926](https://github.com/apollographql/apollo-server/pull/3926) -- `apollo-tracing`: This package is considered deprecated and — along with its `tracing: Boolean` configuration option on the `ApolloServer` constructor options — will cease to exist in Apollo Server 3.x. Until that occurs, we've updated the _internal_ integration of this package with Apollo Server itself to use the newer [request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/), rather than the _also_ soon-to-be-deprecated-`graphql-extensions` API it previously leveraged. The behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991) +- `apollo-tracing`: This package's internal integration with Apollo Server has been switched from using the soon-to-be-deprecated`graphql-extensions` API to using [the request pipeline plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/). Behavior should remain otherwise the same. [PR #3991](https://github.com/apollographql/apollo-server/pull/3991) - **breaking** `apollo-engine-reporting-protobuf`: Drop legacy fields that were never used by `apollo-engine-reporting`. Added new fields `StatsContext` to allow `apollo-server` to send summary stats instead of full traces, and renamed `FullTracesReport` to `Report` and `Traces` to `TracesAndStats` since reports now can include stats as well as traces. ### v2.12.0 From d85276f354b88f6bf8d26e73b7187cb22246d2da Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Fri, 8 May 2020 18:27:38 +0000 Subject: [PATCH 8/8] Switch to new `willResolveField` object parameter, rather position. Implements pattern gained by a926b7eedbb87abab2ec70fb03d7174398 in #3988. Ref: https://github.com/apollographql/apollo-server/pull/3998 --- packages/apollo-tracing/src/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/apollo-tracing/src/index.ts b/packages/apollo-tracing/src/index.ts index 70c541ff7bb..f6ec8a06765 100644 --- a/packages/apollo-tracing/src/index.ts +++ b/packages/apollo-tracing/src/index.ts @@ -62,9 +62,7 @@ export const plugin = (_futureOptions = {}) => (): ApolloServerPlugin => ({ endWallTime = new Date(); }, - willResolveField(...args) { - const [, , , info] = args; - + willResolveField({ info }) { const resolverCall: ResolverCall = { path: info.path, fieldName: info.fieldName,