Repository navigation
console: label each SQL request with its query key in Sentry and the statement log - #40075
Merged
Merged
Conversation
Sentry's browser tracing records one http.client span per fetch, and every console SQL request is a POST to /api/sql, so a trace cannot tell which query made a page slow. executeSqlV2 now records a db.sql.query span named after the scopes of the request's query key, for example clusters.list. Other key parts are left out because they can hold IDs and object names. The span starts only under an existing span, such as a page load or a navigation, so a query that polls in the background never starts a trace of its own and sampling is unchanged. It covers the request and parsing the response, after the environment's address resolves. A request the caller aborted is marked cancelled and a timeout deadline_exceeded, so React Query cancellations do not read as SQL failures. The span is started with startInactiveSpan. In the browser, startSpan with an async callback keeps its scope pushed until the promise settles, so parallel requests would nest under each other.
The statement log records how long each console query took on the server, in every environment, but nothing in the text says which console query it was. executeSqlV2 now appends the request's label as a trailing comment, for example /*console_query='clusters.list'*/, the same label its Sentry span carries. A slow console query in the statement log can then be traced to the console feature that sent it, and grouped by label. The comment goes last because the statement log was observed to drop leading comments and to cut the text at the statement's semicolon, so trailing semicolons are removed first. Only the sql column carries it: redacted_sql is rebuilt from the parsed statement, which has no comments. Query History hides the console's own queries unless console introspection is shown, so customers see the label only when they ask for those queries.
leedqin
marked this pull request as ready for review
October 28, 2026 17:39
leedqin
requested review from
def- and
jdonelson
and removed request for
jdonelson
October 28, 2026 17:39
jdonelson
approved these changes
Nov 3, 2026
| const httpAddress = await getHttpAddress(request); | ||
| // The span starts only under an existing one, such as a page load, so a | ||
| // query that polls in the background never starts a trace of its own. | ||
| // NOTE: `Sentry.startSpan` with an async callback keeps its scope pushed |
Contributor
There was a problem hiding this comment.
I don't think the startSpan nesting can happen here. The browser SDK defaults parentSpanIsAlwaysRootSpan to true, so every span parents to the root span. I tried two parallel requests wrapped in startSpan and they all came out as flat siblings under the page load. Maybe we drop the NOTE? startInactiveSpan is still a fine choice since nothing needs this span to be active.
val-materialize
added a commit
that referenced
this pull request
Nov 13, 2026
Dates in RC snapshots are provisional until the release ships. One commit is added per snapshot; the final snapshot sets the real dates. **The `final` snapshot has been applied: the dates below are the real ones** (Cloud 2026-11-12, Self-Managed 2026-11-13). The `final` snapshot adds no entries — `v26.50.0-rc.1...v26.50.0` is one commit, the version bump, and no agent-skills PR merged in the window. Its substantive work was the dates, a rebase onto `main`, and the three removals below. **Rebased onto `main`.** The branch was 107 commits behind and conflicted: `main`'s `## v26.49.1` section replaced the stale `## v26.49.0` stub the branch was cut from. Resolved by keeping `main`'s section verbatim and re-inserting `## v26.50.0` above it; same for the compatibility YAML (`v26.50`, then `v26.49.1`, then `v26.48.2`). **Three entries removed as already published on `main`.** The `v26.49.1` patch train cherry-picked four Console PRs that also merged to `main` inside this train's `rc.1` window, so both trains classified them independently and `main` already carries them under `## v26.49.1`: | PR(s) | Published on `main` in `## v26.49.1` as | Removed from `## v26.50.0` | |---|---|---| | [#40044](#40044), [#40074](#40074) | the feature section *"Right size your clusters, using the new Hydration tab on the console"*, with a screenshot | *"**Diagnose hydration from the cluster details page**"* | | [#40511](#40511) | *"**Freshness and cluster details pages on Self-Managed**"*, covering both pages | *"**The Freshness page on Self-Managed**"* | | [#40492](#40492) | the Bug Fix about the Console's clusters list showing a dash in the Disk column | *"**Swap usage in the Console's Disk column**"* | `main`'s wording is the later and fuller treatment in all three cases. That leaves `## v26.50.0` with **5 Improvements and 7 Bug Fixes**. Decisions required: - **MCP protocol default flip** ([#39762](#39762)): published as an Improvement because `enable_mcp_protocol_2026_07_28` is `true` at the tag and the flip *is* the change. The PR was held in draft "until the 2026-07-28 code ships in a release and passes a test on a deployed environment" — is it confirmed on? - **Columnar accumulators** ([#40364](#40364)): omitted as Borderline — the default is `true` but the PR states no measured user-facing effect. Is there a memory or CPU figure worth publishing? - **MySQL snapshot/replication concurrency** ([#40206](#40206), [#40207](#40207)): omitted as Borderline — gated on `storage_persist_sink_description_lookahead`, which is `Duration::ZERO` at the tag, same as the PostgreSQL counterparts held back in v26.47.0. If the flag is served on, both halves want announcing together. - **MCP servers GA** ([#40448](#40448)): omitted as Borderline — the preview banners are gone, but the GA call belongs to the release owner. Publish it? - **Balancer connection metrics** ([#40192](#40192)): omitted as Borderline — `mz_balancer_connection_status{status="error"}` changes meaning, so Self-Managed dashboards and alerts on that series will see a step change. Worth a note? - **Console query comments** ([#40075](#40075)): omitted as Borderline — every Console statement's `sql_hash` changes once when this deploys. Worth calling out? Every flag above was re-read in source at the `v26.50.0` ship tag; not one default moved between `rc.1` and ship, so all six holds still read correctly. Snapshot drafts (with PR links) in [mz-skills](https://github.com/MaterializeInc/mz-skills): - rc.1: [release_notes.md](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/rc.1/release_notes.md), [omitted.md](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/rc.1/omitted.md) - final: [release_notes.md](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/final/release_notes.md), [omitted.md](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/final/omitted.md) **Borderline PRs omitted:** rc.1: 7 — [omitted.md#borderline](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/rc.1/omitted.md#borderline), final: 0 — [omitted.md#borderline](https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.50.0/final/omitted.md#borderline) (no PRs in scope; `rc.1`'s six holds re-examined at the ship tag and unchanged) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Pranshu Maheshwari <[email protected]> Co-authored-by: Valerie Chiang <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Sentry's browser tracing records one
http.clientspan per fetch, and every Console SQL request is aPOSTto/api/sql. The query's label only travels in thequery_keyURL parameter, so a sampled page load cannot tell which query made it slow. OnlyfetchClusters, the replicas query and the environment health checks have named spans today.Description
Two commits. Both name a request by its query key's scopes, for example
clusters.list.1. A Sentry span per request.
executeSqlV2records adb.sql.queryspan named after the scopes of the request's query key, for exampleclusters.list, withdb.system: materialize. Sentry groups spans with adbop by name in its Queries view.scopeof each key part goes into the name, because other parts can hold IDs and object names. A key with no scoped part is namedunscoped query.onlyIfParent), such as a page load or a navigation. A query that polls in the background never starts a trace of its own, so sampling and the number of traces are unchanged.cancelled. A timeout isdeadline_exceeded. Any other failure isinternal_error.startInactiveSpan, notstartSpan. In the browser,startSpanwith an async callback keeps its scope pushed until the promise settles, and the stack then pops whichever scope is on top. Parallel requests would nest under each other.2. The same label in the SQL text. Each query gets a trailing comment such as
/*console_query='clusters.list'*/. The statement log already records how long every Console query took on the server, in every environment. With the label in the text, a slow query can be traced to the Console feature that sent it. It can also be grouped by label inmz_recent_activity_log, for example with(regexp_match(sql, 'console_query=''([^'']+)'''))[1].mainbuild, the statement log dropped leading comments and cut the text at the statement's;. Trailing;s are removed first.[A-Za-z0-9_.-]in the label is replaced with_, so no label can end the comment.mz_recent_activity_log.sqlcolumn.redacted_sql, and with itmz_recent_activity_log_redacted, is rebuilt from the parsed statement and has no comments. Anyone who can only read the redacted view won't see the label.sql_hashchanges once. Every Console statement's text, and so itssql_hash, changes when this deploys. Anything that compares Console statements by hash across that release will see them as new statements.executeSql, the SQL Shell and subscribes are unchanged.useSqlTypedalready puts a leading--queryKeycomment, which the statement log drops. The V1 mock handler matches on that comment, so moving it is left for a follow-up.User-visible effect: Console queries in the statement log, and in Query History with console introspection shown, end with a
console_querycomment naming the query.Tests
executeSqlV2.test.tsgains:labelSqlcases for trailing semicolons, a trailing line comment, and characters that could end the comment.queryKeyLabelandspanErrorStatuscases.cancelledEach was checked to fail with the behavior removed.
Open questions
http.clientfetch span. If our Sentry plan bills by span, that adds roughly one span per SQL request in sampled page loads and navigations.fetchClustersandfetchClusterReplicaswrapexecuteSqlV2instartSpanspans that can start root traces for background polls. With this change they duplicate its name. Remove them in a follow-up?queryFnwith keys that differ only in unscoped parts share a name. For example, the deployment lineage lookup and the utilization query both read asreplicaUtilization.🤖 Generated with Claude Code