ref(node): Streamline knex instrumentation#21561
Conversation
Refactors the vendored knex instrumentation off the OpenTelemetry tracing APIs onto Sentry's span APIs, mirroring the mongoose (#21481) and mysql2 (#21509) streamlines. - Replace `tracer.startSpan` + manual `context.with`/`.then`/`.catch` with `startSpan`. `Runner.query` returns a real, already-executing Promise, so `startSpan` can safely await it and auto-end the span while keeping it active so the underlying `pg`/`mysql2` driver spans nest correctly. - Preserve the build-time `contextSymbol` parent + require-parent-span behavior (only instrument queries that run within an existing trace). - Bake the `auto.db.otel.knex` origin into the span attributes and drop the `spanStart` hook from `index.ts`. - Drop the env-gated `OTEL_SEMCONV_STABILITY_OPT_IN` dual-emission; only the OLD semantic conventions (`db.system`, `db.statement`, ...) were ever emitted. Behavior change: the unsupported stable-semconv opt-in is no longer honored. - Hardcode `requireParentSpan`/`maxQueryLength` (the integration only ever used the defaults), delete the now-dead `types.ts`/`constants.ts` and `otelExceptionFromKnexError`, drop OTel `recordException`, and remove the blanket `eslint-disable`. - Extend the `pg` integration suite with a failing query to cover the error path (`status: internal_error`).
125fe11 to
a32abea
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a32abea. Configure here.
nicohrubec
left a comment
There was a problem hiding this comment.
if we can easily already replace the context.with would be good to get that in here as well I think, but else lgtm
| }, | ||
| parentContext, | ||
| const args = arguments; | ||
| return api.context.with(parentContext, () => |
There was a problem hiding this comment.
l: it would be great if we could already rewrite this with Sentry APIs as well
There was a problem hiding this comment.
Nice catch, I did not see that
Replace api.context/api.trace parent detection with getActiveSpan +
startSpan({ parentSpan, onlyIfParent }), and inline the postgresql
semconv constant locally.
| const parentSpan: Span | undefined = this.builder[parentSpanSymbol] || getActiveSpan(); | ||
|
|
||
| const args = arguments; | ||
| return startSpan( | ||
| { | ||
| kind: api.SpanKind.CLIENT, | ||
| name: utils.getName(name, operation, table), | ||
| kind: SpanKind.CLIENT, | ||
| attributes, | ||
| parentSpan, | ||
| onlyIfParent: true, | ||
| }, |
There was a problem hiding this comment.
Bug: Passing an ended span as parentSpan to startSpan bypasses the onlyIfParent: true guard, because the ended span is set as active before the guard is checked.
Severity: MEDIUM
Suggested Fix
Before calling startSpan, validate that the parentSpan is still valid. Reintroduce a check similar to the old implementation, using api.trace.isSpanContextValid(parentSpan.spanContext()) to ensure the span from this.builder[parentSpanSymbol] has not ended before using it as a parent.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
packages/node/src/integrations/tracing/knex/vendored/instrumentation.ts#L149-L159
Potential issue: The `knex` instrumentation stores a parent span when a query builder is
created. This span can be ended by the time the query executes later in a different
async context. This ended span is passed as the `parentSpan` option to `startSpan` with
`onlyIfParent: true`. However, the `startSpan` implementation sets this explicit
`parentSpan` as the active span *before* checking the `onlyIfParent` condition. As a
result, the check finds the (ended) span and incorrectly proceeds, creating a new span
as a child of an ended one, which breaks the trace hierarchy. This replaces a previous
implementation that correctly validated the span context with `isSpanContextValid`.
Did we get this right? 👍 / 👎 to inform future reviews.

Streamlines the vendored knex instrumentation by moving it off the OpenTelemetry tracing APIs onto Sentry's span APIs.
In this integration it was possible to use
startSpandirectly as all APIs seem to be promise based and there is no risk of lazy thenables as far as I can tell.