11import { handleStreamOrSingleExecutionResult , type ExecutionArgs } from '@envelop/core'
2- import { useOnResolve } from '@envelop/on-resolve'
32import tracer , { type opentelemetry , type Span } from 'dd-trace'
4- import { defaultFieldResolver , getNamedType , getOperationAST , type GraphQLResolveInfo } from 'graphql'
3+ import { getOperationAST , type GraphQLResolveInfo } from 'graphql'
54import type { ExecutionResult } from 'graphql-ws'
65import type { Plugin } from 'graphql-yoga'
76import { Path } from 'graphql/jsutils/Path'
@@ -48,43 +47,44 @@ interface Config {
4847export const useDatadogTracing = ( config : Config ) : Plugin < DDContext & ServerContext > => {
4948 if ( process . env . DD_TRACE_ENABLED !== 'true' ) return { }
5049 return {
51- onPluginInit ( { addPlugin} ) {
52- addPlugin (
53- useOnResolve ( ( { info, context, args, replaceResolver, resolver} ) => {
54- // Ignore anything without a custom resolver since it's basically an identity function
55- if ( resolver === defaultFieldResolver ) return
56- const path = getPath ( info , config )
57- const computedPathString = path . join ( '.' )
58- const ddContext = context [ ddSymbol ]
59- const { rootSpan, fields} = ddContext
60- // if collapsed, we just measure the first item in a list
61- if ( config . collapse && fields [ computedPathString ] ) return
50+ // Removing resolve-level tracing to see if we can measure executions without OOMs
51+ // onPluginInit({addPlugin}) {
52+ // addPlugin(
53+ // useOnResolve(({info, context, args, replaceResolver, resolver}) => {
54+ // // Ignore anything without a custom resolver since it's basically an identity function
55+ // if (resolver === defaultFieldResolver) return
56+ // const path = getPath(info, config)
57+ // const computedPathString = path.join('.')
58+ // const ddContext = context[ddSymbol]
59+ // const {rootSpan, fields} = ddContext
60+ // // if collapsed, we just measure the first item in a list
61+ // if (config.collapse && fields[computedPathString]) return
6262
63- const parentSpan = getParentSpan ( path , fields ) ?? rootSpan
64- const { fieldName, returnType, parentType} = info
65- const returnTypeName = getNamedType ( info . returnType ) . name
66- const parentTypeName = getNamedType ( parentType ) . name
67- const fieldSpan = tracer . startSpan ( 'graphql.resolve' , {
68- childOf : parentSpan ,
69- tags : {
70- 'resource.name' : `${ info . fieldName } :${ returnType } ` ,
71- 'span.type' : 'graphql' ,
72- 'graphql.resolver.fieldName' : fieldName ,
73- 'graphql.resolver.typeName' : parentTypeName ,
74- 'graphql.resolver.returnType' : returnTypeName ,
75- 'graphql.resolver.fieldPath' : computedPathString ,
76- ...makeVariables ( config . excludeArgs , args , fieldName )
77- }
78- } )
79- fields [ computedPathString ] = { span : fieldSpan }
80- replaceResolver ( ( ...args ) => tracer . scope ( ) . activate ( fieldSpan , ( ) => resolver ( ...args ) ) )
81- return ( { result} ) => {
82- markSpanError ( fieldSpan , result )
83- fieldSpan . finish ( )
84- }
85- } )
86- )
87- } ,
63+ // const parentSpan = getParentSpan(path, fields) ?? rootSpan
64+ // const {fieldName, returnType, parentType} = info
65+ // const returnTypeName = getNamedType(info.returnType).name
66+ // const parentTypeName = getNamedType(parentType).name
67+ // const fieldSpan = tracer.startSpan('graphql.resolve', {
68+ // childOf: parentSpan,
69+ // tags: {
70+ // 'resource.name': `${info.fieldName}:${returnType}`,
71+ // 'span.type': 'graphql',
72+ // 'graphql.resolver.fieldName': fieldName,
73+ // 'graphql.resolver.typeName': parentTypeName,
74+ // 'graphql.resolver.returnType': returnTypeName,
75+ // 'graphql.resolver.fieldPath': computedPathString,
76+ // ...makeVariables(config.excludeArgs, args, fieldName)
77+ // }
78+ // })
79+ // fields[computedPathString] = {span: fieldSpan}
80+ // replaceResolver((...args) => tracer.scope().activate(fieldSpan, () => resolver(...args)))
81+ // return ({result}) => {
82+ // markSpanError(fieldSpan, result)
83+ // fieldSpan.finish()
84+ // }
85+ // })
86+ // )
87+ // },
8888 onExecute ( { args, extendContext, executeFn, setExecuteFn} ) {
8989 const operationAst = getOperationAST ( args . document , args . operationName ) !
9090 const operationType = operationAst . operation
@@ -110,45 +110,46 @@ export const useDatadogTracing = (config: Config): Plugin<DDContext & ServerCont
110110 } )
111111 }
112112 }
113- } ,
114- onSubscribe ( { args, extendContext, setSubscribeFn, subscribeFn} ) {
115- const operationAst = getOperationAST ( args . document , args . operationName ) !
116- const operationType = operationAst . operation
117- const operationName = operationAst . name ?. value || 'anonymous'
118- const resourceName = `${ operationType } ${ operationName } `
119-
120- const rootSpan = tracer . startSpan ( 'graphql' , {
121- tags : {
122- 'service.name' : 'web-graphql' ,
123- 'resource.name' : resourceName ,
124- 'span.type' : 'graphql' ,
125- 'graphql.subscribe.operationName' : operationName ,
126- 'graphql.subscribe.operationType' : operationType
127- }
128- } )
129- extendContext ( { [ ddSymbol ] : { rootSpan, fields : { } } } )
130- setSubscribeFn ( ( args ) => tracer . scope ( ) . activate ( rootSpan , ( ) => subscribeFn ( args ) ) )
131- return {
132- onSubscribeError : ( { error} ) => {
133- markSpanError ( rootSpan , error )
134- rootSpan . finish ( )
135- } ,
136- onSubscribeResult ( ) {
137- return {
138- onNext : ( { result} ) => {
139- markTopLevelError ( rootSpan , result )
140- } ,
141- onEnd : ( ) => {
142- rootSpan . finish ( )
143- }
144- }
145- }
146- }
147113 }
114+ // Ignoring subscriptions to see if that reduces OOM errors caused by dd-trace
115+ // onSubscribe({args, extendContext, setSubscribeFn, subscribeFn}) {
116+ // const operationAst = getOperationAST(args.document, args.operationName)!
117+ // const operationType = operationAst.operation
118+ // const operationName = operationAst.name?.value || 'anonymous'
119+ // const resourceName = `${operationType} ${operationName}`
120+
121+ // const rootSpan = tracer.startSpan('graphql', {
122+ // tags: {
123+ // 'service.name': 'web-graphql',
124+ // 'resource.name': resourceName,
125+ // 'span.type': 'graphql',
126+ // 'graphql.subscribe.operationName': operationName,
127+ // 'graphql.subscribe.operationType': operationType
128+ // }
129+ // })
130+ // extendContext({[ddSymbol]: {rootSpan, fields: {}}})
131+ // setSubscribeFn((args) => tracer.scope().activate(rootSpan, () => subscribeFn(args)))
132+ // return {
133+ // onSubscribeError: ({error}) => {
134+ // markSpanError(rootSpan, error)
135+ // rootSpan.finish()
136+ // },
137+ // onSubscribeResult() {
138+ // return {
139+ // onNext: ({result}) => {
140+ // markTopLevelError(rootSpan, result)
141+ // },
142+ // onEnd: () => {
143+ // rootSpan.finish()
144+ // }
145+ // }
146+ // }
147+ // }
148+ // }
148149 }
149150}
150151
151- const makeVariables = (
152+ export const makeVariables = (
152153 excludeArgs : Config [ 'excludeArgs' ] ,
153154 variableValues : Record < string , any > | undefined | null ,
154155 fieldName : string
@@ -163,7 +164,7 @@ const makeVariables = (
163164 )
164165}
165166
166- const getParentSpan = ( path : ( string | number ) [ ] , fields : Fields ) => {
167+ export const getParentSpan = ( path : ( string | number ) [ ] , fields : Fields ) => {
167168 const maybeParentPath = path . slice ( 0 , - 1 )
168169 const lastField = maybeParentPath . at ( - 1 )
169170 const parentPath =
@@ -182,15 +183,15 @@ function markTopLevelError(span: tracer.Span | opentelemetry.Span, result: Execu
182183 }
183184}
184185
185- function markSpanError ( span : tracer . Span , error : unknown ) {
186+ export function markSpanError ( span : tracer . Span , error : unknown ) {
186187 if ( error instanceof Error ) {
187188 span . setTag ( 'error.stack' , error . stack )
188189 span . setTag ( 'error.message' , error . message )
189190 span . setTag ( 'error.type' , error . name )
190191 }
191192}
192193
193- function getPath ( info : GraphQLResolveInfo , config : { collapse ?: boolean } ) {
194+ export function getPath ( info : GraphQLResolveInfo , config : { collapse ?: boolean } ) {
194195 const responsePathAsArray = config . collapse ? withCollapse ( pathToArray ) : pathToArray
195196 return responsePathAsArray ( info && info . path )
196197}
0 commit comments