From 62677f606b6cf42064a224aab5e7df669435fae1 Mon Sep 17 00:00:00 2001 From: William Conti Date: Thu, 26 Jun 2025 15:53:51 -0400 Subject: [PATCH 1/4] remove async storage from graphql --- .../datadog-instrumentations/src/graphql.js | 155 ++++++++---------- .../datadog-plugin-graphql/src/execute.js | 17 +- packages/datadog-plugin-graphql/src/parse.js | 15 +- .../datadog-plugin-graphql/src/resolve.js | 23 ++- .../datadog-plugin-graphql/src/validate.js | 16 +- 5 files changed, 115 insertions(+), 111 deletions(-) diff --git a/packages/datadog-instrumentations/src/graphql.js b/packages/datadog-instrumentations/src/graphql.js index c9e6791eecb..ecce010cfe5 100644 --- a/packages/datadog-instrumentations/src/graphql.js +++ b/packages/datadog-instrumentations/src/graphql.js @@ -2,8 +2,7 @@ const { addHook, - channel, - AsyncResource + channel } = require('./helpers/instrument') const shimmer = require('../../datadog-shimmer') @@ -89,10 +88,8 @@ function wrapParse (parse) { return parse.apply(this, arguments) } - const asyncResource = new AsyncResource('bound-anonymous-fn') - - return asyncResource.runInAsyncScope(() => { - parseStartCh.publish() + const ctx = {} + return parseStartCh.runStores(ctx, () => { let document try { document = parse.apply(this, arguments) @@ -107,11 +104,12 @@ function wrapParse (parse) { return document } catch (err) { err.stack - parseErrorCh.publish(err) + ctx.error = err + parseErrorCh.publish(ctx) throw err } finally { - parseFinishCh.publish({ source, document, docSource: documentSources.get(document) }) + parseFinishCh.publish({ source, document, docSource: documentSources.get(document), ...ctx }) } }) } @@ -123,25 +121,24 @@ function wrapValidate (validate) { return validate.apply(this, arguments) } - const asyncResource = new AsyncResource('bound-anonymous-fn') - - return asyncResource.runInAsyncScope(() => { - validateStartCh.publish({ docSource: documentSources.get(document), document }) - + const ctx = { docSource: documentSources.get(document), document } + return validateStartCh.runStores(ctx, () => { let errors try { errors = validate.apply(this, arguments) if (errors && errors[0]) { - validateErrorCh.publish(errors && errors[0]) + ctx.error = errors && errors[0] + validateErrorCh.publish(ctx) } return errors } catch (err) { err.stack - validateErrorCh.publish(err) + ctx.error = err + validateErrorCh.publish(ctx) throw err } finally { - validateFinishCh.publish({ document, errors }) + validateFinishCh.publish({ errors, ...ctx }) } }) } @@ -155,15 +152,15 @@ function wrapExecute (execute) { return exe.apply(this, arguments) } - const asyncResource = new AsyncResource('bound-anonymous-fn') - return asyncResource.runInAsyncScope(() => { - const args = normalizeArgs(arguments, defaultFieldResolver) - const schema = args.schema - const document = args.document - const source = documentSources.get(document) - const contextValue = args.contextValue - const operation = getOperation(document, args.operationName) + const args = normalizeArgs(arguments, defaultFieldResolver) + const schema = args.schema + const document = args.document + const source = documentSources.get(document) + const contextValue = args.contextValue + const operation = getOperation(document, args.operationName) + const ctx = { operation, args, docSource: documentSources.get(document) } + return startExecuteCh.runStores(ctx, () => { if (contexts.has(contextValue)) { return exe.apply(this, arguments) } @@ -173,26 +170,22 @@ function wrapExecute (execute) { wrapFields(schema._mutationType) } - startExecuteCh.publish({ - operation, - args, - docSource: documentSources.get(document) - }) - - const context = { source, asyncResource, fields: {}, abortController: new AbortController() } + const context = { source, fields: {}, abortController: new AbortController(), ...ctx } contexts.set(contextValue, context) - return callInAsyncScope(exe, asyncResource, this, arguments, context.abortController, (err, res) => { + return callInAsyncScope(exe, this, arguments, context.abortController, (err, res) => { if (finishResolveCh.hasSubscribers) finishResolvers(context) const error = err || (res && res.errors && res.errors[0]) if (error) { - executeErrorCh.publish(error) + ctx.error = error + executeErrorCh.publish(ctx) } - finishExecuteCh.publish({ res, args, context }) + ctx.res = res + finishExecuteCh.publish(ctx) }) }) } @@ -211,8 +204,8 @@ function wrapResolve (resolve) { const field = assertField(context, info, args) - return callInAsyncScope(resolve, field.asyncResource, this, arguments, context.abortController, (err) => { - updateFieldCh.publish({ field, info, err }) + return callInAsyncScope(resolve, this, arguments, context.abortController, (err) => { + updateFieldCh.publish({ field, info, err, ...field.ctx }) }) } @@ -221,32 +214,30 @@ function wrapResolve (resolve) { return resolveAsync } -function callInAsyncScope (fn, aR, thisArg, args, abortController, cb) { +function callInAsyncScope (fn, thisArg, args, abortController, cb) { cb = cb || (() => {}) - return aR.runInAsyncScope(() => { - if (abortController?.signal.aborted) { - cb(null, null) - throw new AbortError('Aborted') - } + if (abortController?.signal.aborted) { + cb(null, null) + throw new AbortError('Aborted') + } - try { - const result = fn.apply(thisArg, args) - if (result && typeof result.then === 'function') { - // bind callback to this scope - result.then( - aR.bind(res => cb(null, res)), - aR.bind(err => cb(err)) - ) - } else { - cb(null, result) - } - return result - } catch (err) { - cb(err) - throw err + try { + const result = fn.apply(thisArg, args) + if (result && typeof result.then === 'function') { + // bind callback to this scope + result.then( + res => cb(null, res), + err => cb(err) + ) + } else { + cb(null, result) } - }) + return result + } catch (err) { + cb(err) + throw err + } } function pathToArray (path) { @@ -271,27 +262,15 @@ function assertField (context, info, args) { if (!field) { const parent = getParentField(context, path) - - // we want to spawn the new span off of the parent, not a new async resource - parent.asyncResource.runInAsyncScope(() => { - /* this child resource will run a branched scope off of the parent resource, which - accesses the parent span from the storage unit in its own scope */ - const childResource = new AsyncResource('bound-anonymous-fn') - - childResource.runInAsyncScope(() => { - startResolveCh.publish({ - info, - context, - args - }) - }) - - field = fields[pathString] = { - parent, - asyncResource: childResource, - error: null - } - }) + // we need to pass the parent span to the field if it exists for correct span parenting + // of nested fields + const ctx = { info, context, args, childOf: parent?.ctx?.currentStore?.span } + startResolveCh.publish(ctx) + field = fields[pathString] = { + parent, + error: null, + ctx + } } return field @@ -349,20 +328,16 @@ function wrapFieldType (field) { function finishResolvers ({ fields }) { Object.keys(fields).reverse().forEach(key => { const field = fields[key] - const asyncResource = field.asyncResource - asyncResource.runInAsyncScope(() => { - if (field.error) { - resolveErrorCh.publish(field.error) - } - finishResolveCh.publish(field.finishTime) - }) + const ctx = { field, finishTime: field.finishTime, ...field.ctx } + if (field.error) { + ctx.error = field.error + resolveErrorCh.publish(ctx) + } + finishResolveCh.publish(ctx) }) } -addHook({ name: '@graphql-tools/executor', file: 'cjs/execution/execute.js', versions: ['>=0.0.14'] }, execute => { - shimmer.wrap(execute, 'execute', wrapExecute(execute)) - return execute -}) +addHook({ name: '@graphql-tools/executor', file: 'cjs/execution/execute.js', versions: ['>=0.0.14'] }, execute => {}) addHook({ name: 'graphql', file: 'execution/execute.js', versions: ['>=0.10'] }, execute => { shimmer.wrap(execute, 'execute', wrapExecute(execute)) diff --git a/packages/datadog-plugin-graphql/src/execute.js b/packages/datadog-plugin-graphql/src/execute.js index 638e6e9ca47..3831f7d58dc 100644 --- a/packages/datadog-plugin-graphql/src/execute.js +++ b/packages/datadog-plugin-graphql/src/execute.js @@ -11,7 +11,9 @@ class GraphQLExecutePlugin extends TracingPlugin { static get type () { return 'graphql' } static get kind () { return 'server' } - start ({ operation, args, docSource }) { + bindStart (ctx) { + const { operation, args, docSource } = ctx + const type = operation && operation.operation const name = operation && operation.name && operation.name.value const document = args.document @@ -27,20 +29,25 @@ class GraphQLExecutePlugin extends TracingPlugin { 'graphql.operation.name': name, 'graphql.source': source } - }) + }, ctx) addVariableTags(this.config, span, args.variableValues) + + return ctx.currentStore } - finish ({ res, args }) { - const span = this.activeSpan + finish (ctx) { + const { res, args } = ctx + const span = ctx?.currentStore?.span || this.activeSpan this.config.hooks.execute(span, args, res) if (res?.errors) { for (const err of res.errors) { extractErrorIntoSpanEvent(this._tracerConfig, span, err) } } - super.finish() + super.finish(ctx) + + return ctx.parentStore } } diff --git a/packages/datadog-plugin-graphql/src/parse.js b/packages/datadog-plugin-graphql/src/parse.js index 12669af7a10..1df8f3eab68 100644 --- a/packages/datadog-plugin-graphql/src/parse.js +++ b/packages/datadog-plugin-graphql/src/parse.js @@ -6,16 +6,19 @@ class GraphQLParsePlugin extends TracingPlugin { static get id () { return 'graphql' } static get operation () { return 'parser' } - start () { + bindStart (ctx) { this.startSpan('graphql.parse', { service: this.config.service, type: 'graphql', meta: {} - }) + }, ctx) + + return ctx.currentStore } - finish ({ source, document, docSource }) { - const span = this.activeSpan + finish (ctx) { + const { source, document, docSource } = ctx + const span = ctx?.currentStore?.span || this.activeSpan if (this.config.source && document) { span.setTag('graphql.source', docSource) @@ -23,7 +26,9 @@ class GraphQLParsePlugin extends TracingPlugin { this.config.hooks.parse(span, source, document) - super.finish() + super.finish(ctx) + + return ctx.parentStore } } diff --git a/packages/datadog-plugin-graphql/src/resolve.js b/packages/datadog-plugin-graphql/src/resolve.js index c3f3c13d6c7..3fe27b39091 100644 --- a/packages/datadog-plugin-graphql/src/resolve.js +++ b/packages/datadog-plugin-graphql/src/resolve.js @@ -9,7 +9,8 @@ class GraphQLResolvePlugin extends TracingPlugin { static get id () { return 'graphql' } static get operation () { return 'resolve' } - start ({ info, context, args }) { + start (ctx) { + const { info, context, args, childOf } = ctx const path = getPath(info, this.config) if (!shouldInstrument(this.config, path)) return @@ -35,6 +36,7 @@ class GraphQLResolvePlugin extends TracingPlugin { const span = this.startSpan('graphql.resolve', { service: this.config.service, resource: `${info.fieldName}:${info.returnType}`, + childOf, type: 'graphql', meta: { 'graphql.field.name': info.fieldName, @@ -42,7 +44,7 @@ class GraphQLResolvePlugin extends TracingPlugin { 'graphql.field.type': info.returnType.name, 'graphql.source': source } - }) + }, ctx) if (fieldNode && this.config.variables && fieldNode.arguments) { const variables = this.config.variables(info.variableValues) @@ -58,17 +60,21 @@ class GraphQLResolvePlugin extends TracingPlugin { if (this.resolverStartCh.hasSubscribers) { this.resolverStartCh.publish({ context, resolverInfo: getResolverInfo(info, args) }) } + + return ctx.currentStore } constructor (...args) { super(...args) - this.addTraceSub('updateField', ({ field, info, err }) => { + this.addTraceSub('updateField', (ctx) => { + const { field, info, err } = ctx + const path = getPath(info, this.config) if (!shouldInstrument(this.config, path)) return - const span = this.activeSpan + const span = ctx?.currentStore?.span || this.activeSpan field.finishTime = span._getTime ? span._getTime() : 0 field.error = field.error || err }) @@ -81,8 +87,13 @@ class GraphQLResolvePlugin extends TracingPlugin { super.configure(config.depth === 0 ? false : config) } - finish (finishTime) { - this.activeSpan.finish(finishTime) + bindFinish (ctx) { + const { finishTime } = ctx + + const span = ctx?.currentStore?.span || this.activeSpan + span.finish(finishTime) + + return ctx.parentStore } } diff --git a/packages/datadog-plugin-graphql/src/validate.js b/packages/datadog-plugin-graphql/src/validate.js index 2ed05179b31..bfe3ac9f389 100644 --- a/packages/datadog-plugin-graphql/src/validate.js +++ b/packages/datadog-plugin-graphql/src/validate.js @@ -7,7 +7,8 @@ class GraphQLValidatePlugin extends TracingPlugin { static get id () { return 'graphql' } static get operation () { return 'validate' } - start ({ docSource, document }) { + bindStart (ctx) { + const { docSource, document } = ctx const source = this.config.source && document && docSource this.startSpan('graphql.validate', { @@ -16,18 +17,23 @@ class GraphQLValidatePlugin extends TracingPlugin { meta: { 'graphql.source': source } - }) + }, ctx) + + return ctx.currentStore } - finish ({ document, errors }) { - const span = this.activeSpan + finish (ctx) { + const { document, errors } = ctx + const span = ctx?.currentStore?.span || this.activeSpan this.config.hooks.validate(span, document, errors) if (errors) { for (const err of errors) { extractErrorIntoSpanEvent(this._tracerConfig, span, err) } } - super.finish() + super.finish(ctx) + + return ctx.parentStore } } From 287508b202b6035b3281494b9d43e9887bdab557 Mon Sep 17 00:00:00 2001 From: William Conti Date: Mon, 30 Jun 2025 08:24:08 -0400 Subject: [PATCH 2/4] update graphql --- .../datadog-instrumentations/src/graphql.js | 90 +++++++++---------- .../datadog-plugin-graphql/src/resolve.js | 54 +++++++---- 2 files changed, 79 insertions(+), 65 deletions(-) diff --git a/packages/datadog-instrumentations/src/graphql.js b/packages/datadog-instrumentations/src/graphql.js index ecce010cfe5..8dbc8f001d8 100644 --- a/packages/datadog-instrumentations/src/graphql.js +++ b/packages/datadog-instrumentations/src/graphql.js @@ -88,20 +88,20 @@ function wrapParse (parse) { return parse.apply(this, arguments) } - const ctx = {} + const ctx = { source } return parseStartCh.runStores(ctx, () => { - let document try { - document = parse.apply(this, arguments) - const operation = getOperation(document) + ctx.document = parse.apply(this, arguments) + const operation = getOperation(ctx.document) - if (!operation) return document + if (!operation) return ctx.document if (source) { - documentSources.set(document, source.body || source) + documentSources.set(ctx.document, source.body || source) } + ctx.docSource = documentSources.get(ctx.document) - return document + return ctx.document } catch (err) { err.stack ctx.error = err @@ -109,7 +109,7 @@ function wrapParse (parse) { throw err } finally { - parseFinishCh.publish({ source, document, docSource: documentSources.get(document), ...ctx }) + parseFinishCh.publish(ctx) } }) } @@ -138,7 +138,8 @@ function wrapValidate (validate) { throw err } finally { - validateFinishCh.publish({ errors, ...ctx }) + ctx.errors = errors + validateFinishCh.publish(ctx) } }) } @@ -159,7 +160,14 @@ function wrapExecute (execute) { const contextValue = args.contextValue const operation = getOperation(document, args.operationName) - const ctx = { operation, args, docSource: documentSources.get(document) } + const ctx = { + operation, + args, + docSource: documentSources.get(document), + source, + fields: {}, + abortController: new AbortController() + } return startExecuteCh.runStores(ctx, () => { if (contexts.has(contextValue)) { return exe.apply(this, arguments) @@ -170,12 +178,10 @@ function wrapExecute (execute) { wrapFields(schema._mutationType) } - const context = { source, fields: {}, abortController: new AbortController(), ...ctx } - - contexts.set(contextValue, context) + contexts.set(contextValue, ctx) - return callInAsyncScope(exe, this, arguments, context.abortController, (err, res) => { - if (finishResolveCh.hasSubscribers) finishResolvers(context) + return callInAsyncScope(exe, this, arguments, ctx.abortController, (err, res) => { + if (finishResolveCh.hasSubscribers) finishResolvers(ctx) const error = err || (res && res.errors && res.errors[0]) @@ -198,14 +204,17 @@ function wrapResolve (resolve) { function resolveAsync (source, args, contextValue, info) { if (!startResolveCh.hasSubscribers) return resolve.apply(this, arguments) - const context = contexts.get(contextValue) + const ctx = contexts.get(contextValue) - if (!context) return resolve.apply(this, arguments) + if (!ctx) return resolve.apply(this, arguments) - const field = assertField(context, info, args) + const field = assertField(ctx, info, args) - return callInAsyncScope(resolve, this, arguments, context.abortController, (err) => { - updateFieldCh.publish({ field, info, err, ...field.ctx }) + return callInAsyncScope(resolve, this, arguments, ctx.abortController, (err) => { + field.ctx.error = err + field.ctx.info = info + field.ctx.field = field + updateFieldCh.publish(field.ctx) }) } @@ -250,49 +259,28 @@ function pathToArray (path) { return flattened.reverse() } -function assertField (context, info, args) { +function assertField (parentCtx, info, args) { const pathInfo = info && info.path const path = pathToArray(pathInfo) const pathString = path.join('.') - const fields = context.fields + const fields = parentCtx.fields let field = fields[pathString] if (!field) { - const parent = getParentField(context, path) - // we need to pass the parent span to the field if it exists for correct span parenting - // of nested fields - const ctx = { info, context, args, childOf: parent?.ctx?.currentStore?.span } - startResolveCh.publish(ctx) + const fieldCtx = { info, ctx: parentCtx, args } + startResolveCh.publish(fieldCtx) field = fields[pathString] = { - parent, error: null, - ctx + ctx: fieldCtx } } return field } -function getParentField (context, path) { - for (let i = path.length - 1; i > 0; i--) { - const field = getField(context, path.slice(0, i)) - if (field) { - return field - } - } - - return { - asyncResource: context.asyncResource - } -} - -function getField (context, path) { - return context.fields[path.join('.')] -} - function wrapFields (type) { if (!type || !type._fields || patchedTypes.has(type)) { return @@ -328,12 +316,14 @@ function wrapFieldType (field) { function finishResolvers ({ fields }) { Object.keys(fields).reverse().forEach(key => { const field = fields[key] - const ctx = { field, finishTime: field.finishTime, ...field.ctx } + field.ctx.finishTime = field.finishTime + field.ctx.field = field if (field.error) { - ctx.error = field.error - resolveErrorCh.publish(ctx) + field.ctx.error = field.error + resolveErrorCh.publish(field.ctx) } - finishResolveCh.publish(ctx) + console.log('finishResolvers', field) + finishResolveCh.publish(field.ctx) }) } diff --git a/packages/datadog-plugin-graphql/src/resolve.js b/packages/datadog-plugin-graphql/src/resolve.js index 3fe27b39091..68174a70cdc 100644 --- a/packages/datadog-plugin-graphql/src/resolve.js +++ b/packages/datadog-plugin-graphql/src/resolve.js @@ -9,26 +9,35 @@ class GraphQLResolvePlugin extends TracingPlugin { static get id () { return 'graphql' } static get operation () { return 'resolve' } - start (ctx) { - const { info, context, args, childOf } = ctx - const path = getPath(info, this.config) + start (fieldCtx) { + const { info, ctx: parentCtx, args } = fieldCtx + + const pathInfo = info && info.path + const path = pathToArray(pathInfo) + + // we need to get the parent span to the field if it exists for correct span parenting + // of nested fields + const parentField = getParentField(parentCtx, path) + const childOf = parentField?.ctx?.currentStore?.span + + fieldCtx.parent = parentField if (!shouldInstrument(this.config, path)) return const computedPathString = path.join('.') if (this.config.collapse) { - if (context.fields[computedPathString]) return + if (parentCtx.fields[computedPathString]) return - if (!context[collapsedPathSym]) { - context[collapsedPathSym] = {} - } else if (context[collapsedPathSym][computedPathString]) { + if (!parentCtx[collapsedPathSym]) { + parentCtx[collapsedPathSym] = {} + } else if (parentCtx[collapsedPathSym][computedPathString]) { return } - context[collapsedPathSym][computedPathString] = true + parentCtx[collapsedPathSym][computedPathString] = true } - const document = context.source + const document = parentCtx.source const fieldNode = info.fieldNodes.find(fieldNode => fieldNode.kind === 'Field') const loc = this.config.source && document && fieldNode && fieldNode.loc const source = loc && document.slice(loc.start, loc.end) @@ -44,7 +53,7 @@ class GraphQLResolvePlugin extends TracingPlugin { 'graphql.field.type': info.returnType.name, 'graphql.source': source } - }, ctx) + }, fieldCtx) if (fieldNode && this.config.variables && fieldNode.arguments) { const variables = this.config.variables(info.variableValues) @@ -58,17 +67,17 @@ class GraphQLResolvePlugin extends TracingPlugin { } if (this.resolverStartCh.hasSubscribers) { - this.resolverStartCh.publish({ context, resolverInfo: getResolverInfo(info, args) }) + this.resolverStartCh.publish({ ctx: parentCtx, resolverInfo: getResolverInfo(info, args) }) } - return ctx.currentStore + return fieldCtx.currentStore } constructor (...args) { super(...args) this.addTraceSub('updateField', (ctx) => { - const { field, info, err } = ctx + const { field, info, error } = ctx const path = getPath(info, this.config) @@ -76,7 +85,7 @@ class GraphQLResolvePlugin extends TracingPlugin { const span = ctx?.currentStore?.span || this.activeSpan field.finishTime = span._getTime ? span._getTime() : 0 - field.error = field.error || err + field.error = field.error || error }) this.resolverStartCh = dc.channel('datadog:graphql:resolver:start') @@ -87,7 +96,7 @@ class GraphQLResolvePlugin extends TracingPlugin { super.configure(config.depth === 0 ? false : config) } - bindFinish (ctx) { + finish (ctx) { const { finishTime } = ctx const span = ctx?.currentStore?.span || this.activeSpan @@ -165,4 +174,19 @@ function getResolverInfo (info, args) { return resolverInfo } +function getParentField (parentCtx, path) { + for (let i = path.length - 1; i > 0; i--) { + const field = getField(parentCtx, path.slice(0, i)) + if (field) { + return field + } + } + + return null +} + +function getField (parentCtx, path) { + return parentCtx.fields[path.join('.')] +} + module.exports = GraphQLResolvePlugin From adc60401bb1a9236e7052e2034f13d6711731cae Mon Sep 17 00:00:00 2001 From: William Conti Date: Mon, 14 Jul 2025 15:03:17 -0400 Subject: [PATCH 3/4] fix failing tests --- packages/datadog-instrumentations/src/graphql.js | 1 - packages/datadog-plugin-graphql/src/resolve.js | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/datadog-instrumentations/src/graphql.js b/packages/datadog-instrumentations/src/graphql.js index 3e637ff46e3..7418c9da575 100644 --- a/packages/datadog-instrumentations/src/graphql.js +++ b/packages/datadog-instrumentations/src/graphql.js @@ -322,7 +322,6 @@ function finishResolvers ({ fields }) { field.ctx.error = field.error resolveErrorCh.publish(field.ctx) } - console.log('finishResolvers', field) finishResolveCh.publish(field.ctx) }) } diff --git a/packages/datadog-plugin-graphql/src/resolve.js b/packages/datadog-plugin-graphql/src/resolve.js index 68174a70cdc..c22b34f37c4 100644 --- a/packages/datadog-plugin-graphql/src/resolve.js +++ b/packages/datadog-plugin-graphql/src/resolve.js @@ -12,12 +12,11 @@ class GraphQLResolvePlugin extends TracingPlugin { start (fieldCtx) { const { info, ctx: parentCtx, args } = fieldCtx - const pathInfo = info && info.path - const path = pathToArray(pathInfo) + const path = getPath(info, this.config) // we need to get the parent span to the field if it exists for correct span parenting // of nested fields - const parentField = getParentField(parentCtx, path) + const parentField = getParentField(parentCtx, pathToArray(info && info.path)) const childOf = parentField?.ctx?.currentStore?.span fieldCtx.parent = parentField From 51a2c6d40a4bde84e154d46f2f78633fd9786668 Mon Sep 17 00:00:00 2001 From: William Conti Date: Mon, 14 Jul 2025 15:11:17 -0400 Subject: [PATCH 4/4] fix lint --- packages/datadog-instrumentations/src/graphql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/datadog-instrumentations/src/graphql.js b/packages/datadog-instrumentations/src/graphql.js index 7418c9da575..30f3c8cc137 100644 --- a/packages/datadog-instrumentations/src/graphql.js +++ b/packages/datadog-instrumentations/src/graphql.js @@ -37,7 +37,7 @@ const validateFinishCh = channel('apm:graphql:validate:finish') const validateErrorCh = channel('apm:graphql:validate:error') class AbortError extends Error { - constructor(message) { + constructor (message) { super(message) this.name = 'AbortError' }