diff --git a/plugins/node/opentelemetry-instrumentation-graphql/.tav.yml b/plugins/node/opentelemetry-instrumentation-graphql/.tav.yml index a80a1f590e..603ce40daf 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/.tav.yml +++ b/plugins/node/opentelemetry-instrumentation-graphql/.tav.yml @@ -1,4 +1,4 @@ graphql: - # Taking a sample from the most downloaded versions in the range "14 || 15" - versions: "^15.8.0 || 15.7.2 || 15.6.1 || 15.6.0 || 15.5.3 || 15.5.1 || 15.5.0 || 15.4.0 || 15.3.0 || 14.6.0 || 14.5.8 || 14.5.0 || 14.0.0" + # Taking a sample from the most downloaded versions in the range "14 || 15 || 16" + versions: "16.4.0 || 16.3.0 || 16.2.0 || 16.0.0 || ^15.8.0 || 15.7.2 || 15.6.1 || 15.6.0 || 15.5.3 || 15.5.1 || 15.5.0 || 15.4.0 || 15.3.0 || ^14.7.0 || 14.6.0 || 14.5.8 || 14.0.0" commands: npm run test diff --git a/plugins/node/opentelemetry-instrumentation-graphql/package.json b/plugins/node/opentelemetry-instrumentation-graphql/package.json index 414c70fb61..0777ea5682 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/package.json +++ b/plugins/node/opentelemetry-instrumentation-graphql/package.json @@ -44,13 +44,15 @@ "access": "public" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": "^1.0.0", + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" }, "devDependencies": { "@opentelemetry/api": "^1.0.0", "@opentelemetry/sdk-trace-base": "^1.3.1", "@types/mocha": "8.2.3", "@types/node": "16.11.21", + "graphql": "^16.5.0", "gts": "3.1.0", "mocha": "7.2.0", "nyc": "15.1.0", @@ -60,8 +62,7 @@ "typescript": "4.3.5" }, "dependencies": { - "@opentelemetry/instrumentation": "^0.32.0", - "graphql": "^15.5.1" + "@opentelemetry/instrumentation": "^0.32.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-graphql#readme" } diff --git a/plugins/node/opentelemetry-instrumentation-graphql/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-graphql/src/instrumentation.ts index 52c7465a2f..efb54b6c87 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-graphql/src/instrumentation.ts @@ -307,8 +307,8 @@ export class GraphQLInstrumentation extends InstrumentationBase { schema: graphqlTypes.GraphQLSchema, documentAST: graphqlTypes.DocumentNode, rules?: ReadonlyArray, - typeInfo?: graphqlTypes.TypeInfo, - options?: { maxErrors?: number } + options?: { maxErrors?: number }, + typeInfo?: graphqlTypes.TypeInfo ): ReadonlyArray { return instrumentation._validate( this, @@ -373,8 +373,8 @@ export class GraphQLInstrumentation extends InstrumentationBase { schema, documentAST, rules, - typeInfo, - options + options, + typeInfo ); }, (err, errors) => { diff --git a/plugins/node/opentelemetry-instrumentation-graphql/src/types.ts b/plugins/node/opentelemetry-instrumentation-graphql/src/types.ts index 7f457dafcf..f783140bed 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-graphql/src/types.ts @@ -120,8 +120,8 @@ export type validateType = ( schema: graphqlTypes.GraphQLSchema, documentAST: graphqlTypes.DocumentNode, rules?: ReadonlyArray, - typeInfo?: graphqlTypes.TypeInfo, - options?: { maxErrors?: number } + options?: { maxErrors?: number }, + typeInfo?: graphqlTypes.TypeInfo ) => ReadonlyArray; export interface GraphQLField { diff --git a/plugins/node/opentelemetry-instrumentation-graphql/src/utils.ts b/plugins/node/opentelemetry-instrumentation-graphql/src/utils.ts index 052953a5e5..0a938dfb72 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-graphql/src/utils.ts @@ -387,7 +387,13 @@ export function wrapFieldResolver( > >( () => { - return fieldResolver.call(this, source, args, contextValue, info); + return fieldResolver.call( + this, + source, + args, + contextValue, + info + ) as any; }, err => { if (shouldEndSpan) { @@ -421,7 +427,7 @@ async function safeExecuteInTheMiddleAsync( try { result = await execute(); } catch (e) { - error = e; + error = e as Error; } finally { onFinish(error, result); if (error && !preventThrowingError) { diff --git a/plugins/node/opentelemetry-instrumentation-graphql/test/graphql-adaptor.ts b/plugins/node/opentelemetry-instrumentation-graphql/test/graphql-adaptor.ts new file mode 100644 index 0000000000..c0ccac4848 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-graphql/test/graphql-adaptor.ts @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { + GraphQLFieldResolver, + GraphQLSchema, + GraphQLTypeResolver, + Source, +} from 'graphql'; +import { graphql as origGraphql, version } from 'graphql'; +import { Maybe } from 'graphql/jsutils/Maybe'; + +const variantGraphql = origGraphql as Function; + +interface GraphQLArgs { + schema: GraphQLSchema; + source: string | Source; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: Maybe<{ + readonly [variable: string]: unknown; + }>; + operationName?: Maybe; + fieldResolver?: Maybe>; + typeResolver?: Maybe>; +} + +export const graphql = (args: GraphQLArgs) => + !version || version.startsWith('14.') || version.startsWith('15.') + ? variantGraphql( + args.schema, + args.source, + args.rootValue, + args.contextValue, + args.variableValues, + args.operationName, + args.fieldResolver, + args.typeResolver + ) + : variantGraphql(args); diff --git a/plugins/node/opentelemetry-instrumentation-graphql/test/graphql.test.ts b/plugins/node/opentelemetry-instrumentation-graphql/test/graphql.test.ts index 5d54744f2a..abdf338112 100644 --- a/plugins/node/opentelemetry-instrumentation-graphql/test/graphql.test.ts +++ b/plugins/node/opentelemetry-instrumentation-graphql/test/graphql.test.ts @@ -40,7 +40,7 @@ graphQLInstrumentation.disable(); // now graphql can be required import { buildSchema } from './schema'; -import { graphql } from 'graphql'; +import { graphql } from './graphql-adaptor'; // Construct a schema, using GraphQL schema language const schema = buildSchema(); @@ -107,7 +107,7 @@ describe('graphql', () => { let spans: ReadableSpan[]; beforeEach(async () => { create({}); - await graphql(schema, sourceList1); + await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -235,7 +235,7 @@ describe('graphql', () => { beforeEach(async () => { create({}); - await graphql(schema, sourceBookById); + await graphql({ schema, source: sourceBookById }); spans = exporter.getFinishedSpans(); }); @@ -323,8 +323,12 @@ describe('graphql', () => { beforeEach(async () => { create({}); - await graphql(schema, sourceFindUsingVariable, null, null, { - id: 2, + await graphql({ + schema, + source: sourceFindUsingVariable, + variableValues: { + id: 2, + }, }); spans = exporter.getFinishedSpans(); }); @@ -421,7 +425,7 @@ describe('graphql', () => { create({ depth: 0, }); - await graphql(schema, sourceList1); + await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -489,7 +493,7 @@ describe('graphql', () => { create({ mergeItems: true, }); - await graphql(schema, sourceList1); + await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -556,7 +560,7 @@ describe('graphql', () => { mergeItems: true, depth: 0, }); - await graphql(schema, sourceList1); + await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -580,7 +584,7 @@ describe('graphql', () => { create({ allowValues: true, }); - await graphql(schema, sourceBookById); + await graphql({ schema, source: sourceBookById }); spans = exporter.getFinishedSpans(); }); @@ -670,7 +674,7 @@ describe('graphql', () => { create({ allowValues: true, }); - await graphql(schema, sourceAddBook); + await graphql({ schema, source: sourceAddBook }); spans = exporter.getFinishedSpans(); }); @@ -764,8 +768,12 @@ describe('graphql', () => { create({ allowValues: true, }); - await graphql(schema, sourceFindUsingVariable, null, null, { - id: 2, + await graphql({ + schema, + source: sourceFindUsingVariable, + variableValues: { + id: 2, + }, }); spans = exporter.getFinishedSpans(); }); @@ -862,7 +870,7 @@ describe('graphql', () => { create({ // allowValues: true }); - await graphql(schema, sourceAddBook); + await graphql({ schema, source: sourceAddBook }); spans = exporter.getFinishedSpans(); }); @@ -955,7 +963,7 @@ describe('graphql', () => { beforeEach(async () => { create({}); - await graphql(schema, badQuery); + await graphql({ schema, source: badQuery }); spans = exporter.getFinishedSpans(); }); @@ -990,7 +998,7 @@ describe('graphql', () => { beforeEach(async () => { create({}); - await graphql(schema, queryInvalid); + await graphql({ schema, source: queryInvalid }); spans = exporter.getFinishedSpans(); }); @@ -1036,7 +1044,7 @@ describe('graphql', () => { describe('responseHook', () => { let spans: ReadableSpan[]; - let graphqlResult: graphqlTypes.ExecutionResult; + let graphqlResult: graphqlTypes.ExecutionResult<{ books: unknown[] }>; const dataAttributeName = 'graphql_data'; afterEach(() => { @@ -1052,7 +1060,7 @@ describe('graphql', () => { span.setAttribute(dataAttributeName, JSON.stringify(data)); }, }); - graphqlResult = await graphql(schema, sourceList1); + graphqlResult = await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -1075,7 +1083,7 @@ describe('graphql', () => { throw 'some kind of failure!'; }, }); - graphqlResult = await graphql(schema, sourceList1); + graphqlResult = await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); }); @@ -1092,7 +1100,7 @@ describe('graphql', () => { responseHook: invalidTypeHook as GraphQLInstrumentationExecutionResponseHook, }); - graphqlResult = await graphql(schema, sourceList1); + graphqlResult = await graphql({ schema, source: sourceList1 }); spans = exporter.getFinishedSpans(); });