feat(server-utils): Instrument graphql v17 via native tracing channels#21804
feat(server-utils): Instrument graphql v17 via native tracing channels#21804logaretm wants to merge 4 commits into
Conversation
size-limit report 📦
|
2407b9e to
31520be
Compare
c907efa to
3da22d3
Compare
| span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); | ||
| } | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Root span rename missing v17
Medium Severity
On GraphQL 17, tracing uses the diagnostics-channel path only, but useOperationNameForRootSpan (default true on graphqlIntegration) is never applied there. The vendored OTel instrumentation that renames the enclosing HTTP root span is gated to GraphQL < 17, so upgrading GraphQL while keeping the same SDK option leaves server transaction names unchanged.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit abebece. Configure here.
…nnel tracing channels Adds a graphqlChannelIntegration in server-utils that subscribes to graphql >= 17's native node:diagnostics_channel tracing channels (graphql:parse / :validate / :execute / :subscribe) and builds spans with the graphql semantic conventions. The node graphqlIntegration extends it via extendIntegration so the vendored OTel patcher still handles graphql < 17. Per-field graphql:resolve spans are omitted (high volume; the OTel path also defaults them off).
…pans option Wires the per-field `graphql:resolve` channel into the graphql diagnostics-channel subscriber, gated behind the existing `ignoreResolveSpans` option (default true, so off by default). When enabled, `ignoreTrivialResolveSpans` (default true) additionally skips graphql's default property resolver. Both options now flow through to the channel path, matching the vendored OTel patcher's behavior on graphql < 17.
…keeping Split option-matrix tests into process-isolated files instead of resetting and re-subscribing the process-global channels.
…tion Runtimes that use the server-utils integration directly expose it to users, so 'channel' in the name leaks an implementation detail. Node imports it under an internal alias since it keeps its own composed graphqlIntegration.
abebece to
3f660c0
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3f660c0. Configure here.
| // The factory relies on `node:diagnostics_channel`, which isn't always | ||
| // available. Fail closed; the SDK simply won't emit graphql spans here. | ||
| DEBUG_BUILD && debug.log('GraphQL node:diagnostics_channel subscription failed.'); | ||
| } |
There was a problem hiding this comment.
Failed subscribe blocks forever
Low Severity
subscribed is set to true before channel setup finishes. If the surrounding try throws partway through or in the catch path, later calls to subscribeGraphqlDiagnosticChannels return immediately and GraphQL tracing never comes online for that process.
Reviewed by Cursor Bugbot for commit 3f660c0. Configure here.


GraphQL v17 uses its native
diagnostics_channelfor tracing instead of monkey-patching. It publishes lifecycle events on:graphql:parsegraphql:validategraphql:executegraphql:subscribeThis PR adds new
graphqlChannelIntegrationin server-utils that subscribes to these events and builds spans with graphql semantic conventions. ThegraphqlIntegrationnode extends this integration and keeps the vendored OTel patcher for graphql < 17. The patcher is gated>=14 <17.A couple of things worth calling out:
graphql.documentvalue is the original query text with inline literal arguments redacted ("foo"→"*",42→*) so raw values can't leak, and variable values are never attached.graphql:resolvespans are off by default because they're very high volume, users can opt in viaignoreResolveSpansjust like previous versions.