Skip to content

feat(server-utils): Set db.operation.name on SQL spans - #25850

Merged
mydea merged 3 commits into
developfrom
feat/db-operation-name
Oct 30, 2026
Merged

mydea merged 3 commits into
developfrom
feat/db-operation-name

Conversation

@mydea

@mydea mydea commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

I noticed this when bumping junior from v10 to v11, that we are not setting these in some of our db instrumentation.

Why: pg, mysql, mysql2, tedious, neon, Prisma and Nuxt's db0 spans had db.query.summary but no db.operation.name, while postgres.js, knex, MongoDB, Redis etc. already set it. That made grouping/alerting by operation inconsistent across DB integrations. The operation is parsed from the sanitized query by a shared helper next to the summary logic, keeping the original case as OTel recommends.

How to review: Start with getSqlOperationName in utils/sql.ts; the integration changes are one-liners. Neon batches follow the OTel rule (BATCH <op> if all statements share one operation, else BATCH).

Unsure about: For WITH queries I report the main statement's keyword (the first one outside the parenthesized CTE bodies) rather than WITH. Depth counting is safe because it runs on the sanitized query, which has no literals or comments left. tedious callProcedure is left without an operation. postgres.js still uppercases its value; I didn't migrate it to avoid a behavior change here.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Compared: 90450a6 (PR test merge using develop at 2f5a2f9)

Against: 2f5a2f9 (develop) · base run #64409

✅ Baseline matches: this diff contains only this PR's changes.

Path Size % Change Change
@sentry/browser 30.39 kB - -
@sentry/browser - with treeshaking flags 28.53 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 28.42 kB - -
@sentry/browser (incl. Tracing) 52.7 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 52.71 kB - -
@sentry/browser (incl. Tracing, Profiling) 55.68 kB - -
@sentry/browser (incl. Tracing, Replay) 93.01 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 81.6 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 97.75 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 110.74 kB - -
@sentry/browser (incl. Feedback) 47.97 kB - -
@sentry/browser (incl. sendFeedback) 35.49 kB - -
@sentry/browser (incl. FeedbackAsync) 40.6 kB - -
@sentry/browser (incl. Metrics) 31.42 kB - -
@sentry/browser (incl. Logs) 31.72 kB - -
@sentry/browser (incl. Metrics & Logs) 32.44 kB - -
@sentry/react 32.27 kB - -
@sentry/react (incl. Tracing) 55.07 kB - -
@sentry/vue 38.66 kB - -
@sentry/vue (incl. Tracing) 55.72 kB - -
@sentry/svelte 30.42 kB - -
@sentry/remix (Remix 3 client bundle) 57.79 kB - -
CDN Bundle 32.18 kB - -
CDN Bundle (incl. Tracing) 53.23 kB - -
CDN Bundle (incl. Logs, Metrics) 34.45 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 55.17 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 75.86 kB - -
CDN Bundle (incl. Tracing, Replay) 91.44 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 93.38 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 97.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 99.55 kB - -
CDN Bundle - uncompressed 94.62 kB - -
CDN Bundle (incl. Tracing) - uncompressed 157.58 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 101.09 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 163.31 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 232.65 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 279.27 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 284.99 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 292.97 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 298.69 kB - -
@sentry/nextjs (client) 57.87 kB - -
@sentry/sveltekit (client) 53.22 kB - -
@sentry/core/server 44.24 kB - -
@sentry/core/browser 13.93 kB - -
@sentry/node 155.18 kB +0.2% +299 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.08 kB - -
@sentry/node - without tracing 96.23 kB +0.03% +21 B 🔺
@sentry/node - without channel injection 135.58 kB +0.21% +271 B 🔺
@sentry/aws-serverless 104.42 kB +0.03% +26 B 🔺
@sentry/cloudflare (withSentry) - minified 197.91 kB +0.02% +22 B 🔺
@sentry/cloudflare (withSentry) 491.89 kB +0.01% +23 B 🔺
@sentry/nextjs/cloudflare (withSentry) - minified 218.34 kB +0.02% +22 B 🔺

View base workflow run

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Optional E2E tests

Some optional checks were not successful. They do not block the merge. 5 not successful, 47 successful. See the run.

Check Status
❌ CI: Optional E2E Tests / E2E cloudflare-think Test (optional) Failing after 6s Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (cloudflare, latest) Test (optional) Failing after 3s Details
❌ CI: Optional E2E Tests / E2E gen-ai-libraries (latest) Test (optional) Failing after 35s Details
❌ CI: Optional E2E Tests / E2E node-express-send-to-sentry-static Test (optional) Failing after 5s Details
❌ CI: Optional E2E Tests / E2E nuxt-5 Test (optional) Failing after 2m Details
Successful checks
Check Status
✅ CI: Optional E2E Tests / E2E cloudflare-pi-durable Test (optional) Successful in 23s Details
✅ CI: Optional E2E Tests / E2E cloudflare-pi-durable (latest) Test (optional) Successful in 29s Details
✅ CI: Optional E2E Tests / E2E deno (latest) Test (optional) Successful in 47s Details
✅ CI: Optional E2E Tests / E2E nestjs-12 (latest) Test (optional) Successful in 35s Details
✅ CI: Optional E2E Tests / E2E astro-7 Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E supabase-nextjs Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E cloudflare-mastra Test (optional) Successful in 28s Details
✅ CI: Optional E2E Tests / E2E node-eve Test (optional) Successful in 42s Details
✅ CI: Optional E2E Tests / E2E nextjs-14 (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E cloudflare-agent Test (optional) Successful in 25s Details
✅ CI: Optional E2E Tests / E2E node-eve (orchestrion) Test (optional) Successful in 41s Details
✅ CI: Optional E2E Tests / E2E cloudflare-think (ai v6) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E gen-ai-libraries (cloudflare) Test (optional) Successful in 23s Details
✅ CI: Optional E2E Tests / E2E nextjs-16 (vinext) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nextjs-15 (turbo) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E cloudflare-workers-send-to-sentry Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E nextjs-16 (deno) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E debug-id-sourcemaps Test (optional) Successful in 26s Details
✅ CI: Optional E2E Tests / E2E gen-ai-libraries Test (optional) Successful in 34s Details
✅ CI: Optional E2E Tests / E2E nextjs-16-tunnel (cloudflare) Test (optional) Successful in 48s Details
✅ CI: Optional E2E Tests / E2E cloudflare-flue-send-to-sentry Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E astro-7-static Test (optional) Successful in 46s Details
✅ CI: Optional E2E Tests / E2E node-express-mcp-v2 Test (optional) Successful in 20s Details
✅ CI: Optional E2E Tests / E2E nextjs-orpc Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-flue (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-fastify-6 (tracer provider) Test (optional) Successful in 24s Details
✅ CI: Optional E2E Tests / E2E node-pi-durable Test (optional) Successful in 26s Details
✅ CI: Optional E2E Tests / E2E node-flue Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-express-send-to-sentry Test (optional) Successful in 49s Details
✅ CI: Optional E2E Tests / E2E nextjs-16 (vinext, bun) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-fastify-6 Test (optional) Successful in 22s Details
✅ CI: Optional E2E Tests / E2E tanstackstart-react-cloudflare Test (optional) Successful in 23s Details
✅ CI: Optional E2E Tests / E2E nextjs-15 (latest) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps (client source maps kept) Test (optional) Successful in 22s Details
✅ CI: Optional E2E Tests / E2E node-express-mcp-v1 Test (optional) Successful in 20s Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps Test (optional) Successful in 23s Details
✅ CI: Optional E2E Tests / E2E node-openai-decisions Test (optional) Successful in 15s Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps (static / nuxt generate) Test (optional) Successful in 24s Details
✅ CI: Optional E2E Tests / E2E node-eve (latest) Test (optional) Successful in 41s Details
✅ CI: Optional E2E Tests / E2E node-mastra Test (optional) Successful in 51s Details
✅ CI: Optional E2E Tests / E2E solidstart-2 Test (optional) Successful in 41s Details
✅ CI: Optional E2E Tests / E2E node-openai-decisions (latest) Test (optional) Successful in 25s Details
✅ CI: Optional E2E Tests / E2E react-router-7-framework-instrumentation Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-pi-durable (latest) Test (optional) Successful in 25s Details
✅ CI: Optional E2E Tests / E2E node-mastra (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E tanstackstart-react (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E tanstackstart-react-sourcemaps Test (optional) Successful in 30s Details

@mydea
mydea marked this pull request as ready for review October 29, 2026 08:07
@mydea
mydea requested review from a team as code owners October 29, 2026 08:07
@mydea
mydea requested review from andreiborza, chargome, isaacs and nicohrubec and removed request for a team October 29, 2026 08:07
Comment thread packages/server-utils/src/utils/sql.ts Resolved
Comment thread packages/server-utils/src/utils/sql.ts Resolved
};
}

// OTel names a batch `BATCH <op>` when every statement shares one operation, plain `BATCH` otherwise.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Should we add that as an example/rule to the conventions?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mydea

mydea commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

@nicohrubec I took your feedback and actually put this into a dedicated PR stacked on top: #25927 as this would otherwise make it a bit tricky to see what changes where/why. That renames the utility to a more sensible name after the changes, and actually streamlines this a bit so we can mostly spread these query attributes in and have this consistent everywhere!

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/server-utils/src/utils/sql.ts Resolved
@mydea
mydea force-pushed the feat/db-operation-name branch from 6030ddd to 9b71099 Compare October 30, 2026 09:32

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f2129aa. Configure here.

Comment thread packages/server-utils/src/utils/sql.ts Resolved

@nicohrubec nicohrubec left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

mydea and others added 3 commits October 30, 2026 13:44
pg, mysql, mysql2, tedious, neon, Prisma and the Nuxt db0 integration
now derive `db.operation.name` from the sanitized query, matching what
postgres.js, knex and the document stores already report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T-SQL's ;WITH

The operation of a WITH query is its main statement, not the first DML
keyword inside a CTE. Leading semicolons are now stripped by the sanitizer,
so T-SQL's `;WITH` queries get an operation name too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The leading keyword skips parentheses that wrap the whole query, so the CTE
scan now starts after `WITH` instead of counting them too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mydea
mydea force-pushed the feat/db-operation-name branch from 5718dfe to 1e9b545 Compare October 30, 2026 12:45
@mydea
mydea merged commit b52901e into develop Oct 30, 2026
556 of 568 checks passed
@mydea
mydea deleted the feat/db-operation-name branch October 30, 2026 13:15
mydea added a commit that referenced this pull request Oct 30, 2026
…nsistency (#25927)

**Why:** `sanitizeSqlQueryWithSummary` grew a third value with
`db.operation.name`, and every SQL integration copied the result into
the same three attributes by hand. `getSqlQueryAttributes` returns them
keyed by attribute name, so integrations spread it and the keys can't
drift. The mysql2 diagnostics-channel subscriber and postgres.js drop
their own operation regexes for the shared helper, so their
`db.operation.name` keeps the statement's case and resolves CTEs like
the other integrations (postgres.js still prefers the server-reported
command once a query succeeds). postgres.js also no longer reports the
sanitizer's `Unknown SQL Query` placeholder as `db.query.text` when
there is no query; its public `requestHook` gets `''` in that case.

**How to review:** Start with `utils/sql.ts`, then the Prisma tracing
helper. Prisma keeps its own `db.query.text`/`db.operation.name` and
only falls back to ours; `db.query.summary` is always ours, so the
streamed span name stays dialect-aware across Prisma versions. Prisma 5
only reports `db.statement`, so its spans now also get a sanitized
`db.query.text` (see the v5 test). Tedious clears the summary and
operation name for procedure calls, as before.

**Unsure about:** `@sentry/server-utils` exports the renamed helper, but
the package is internal (no SemVer guarantee) and Nuxt pins it exactly,
so I didn't keep an alias.

Stacked on #25850.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants