Skip to content

feat(dashboard): surface additional query metrics in the drill-down - #386

Open
dpage wants to merge 1 commit into
fix/issue-335-top-queries-paginationfrom
fix/issue-350-query-metrics
Open

feat(dashboard): surface additional query metrics in the drill-down#386
dpage wants to merge 1 commit into
fix/issue-335-top-queries-paginationfrom
fix/issue-350-query-metrics

Conversation

@dpage

@dpage dpage commented Jul 29, 2026

Copy link
Copy Markdown
Member

Stacked on #379. This PR targets fix/issue-335-top-queries-pagination, so the diff shown is only the #350 work. It will retarget to main automatically once #379 merges. Please review #379 first.

Summary

Implements issue #350, bar the client IP / hostname, which turned out not to be achievable without a collector change and is tracked separately as #384.

  • Min and max execution time KPI tiles in the query drill-down; both values were already collected, so this is plumbing.
  • A range-scoped average execution time tile, labelled with the selected range (for example "Avg Time (Last 24h)") so it cannot be confused with the cumulative lifetime mean beside it, which is now labelled "Mean Time (All Time)". It is served by a new GET /api/v1/metrics/query-stats, computed as the sum of per-sample deltas rather than a first-versus-last subtraction, so a pg_stat_reset() or restart part way through the range costs one interval instead of corrupting the whole figure. It returns null, not zero, when there is no usable data.
  • The database role that ran the query, shown beside the query text. Resolved from pg_stat_activity via a usesysid lookup mirroring the existing datid resolution; falls back to "Unknown", since resolution only works for roles observed with an active backend inside the retention window.
  • A bug fix: the drill-down's execution-time and call-count charts sent no query filter, so they aggregated across every statement on the connection rather than the query being inspected. GET /api/v1/metrics/query gains an optional queryid filter, which rejects probes lacking that column rather than emitting invalid SQL.

Behaviour change worth a reviewer's eye

The database-name lookup CTE now picks the most recently observed name per OID (DISTINCT ON (datid) ... ORDER BY datid, collected_at DESC) instead of an arbitrary one. Previously a database renamed within the retention window could report either name depending on which the planner reached first, so this makes an existing wobble deterministic rather than introducing new behaviour.

Test plan

  • New QueryDetail.test.tsx (there was none) covering the new tiles, the null average path, the unresolved-username path, queryid reaching the chart requests, and refetch on time-range change.
  • New server tests for the query-stats endpoint including the counter-reset and no-data paths, the queryid filter on both the time-series and latest-row paths, and username resolution including the unresolvable case.
  • Coverage on touched units: handleQueryStats, buildQueryStats, buildTopQueriesSQL, metricQueryBase, buildLatestRowsQuery all 100%; QueryDetail.tsx 99.0%; useQueryStats.ts and useMetrics.ts 100%.
  • go test -race ./internal/api/ ./internal/metrics/ and the client suite (27 files, 521 tests) both pass; gofmt, golangci-lint and npm run lint clean.

Closes #350

Adds the metrics requested in #350, bar the client IP, which is not
achievable without a collector change and is tracked separately.

The query drill-down now shows minimum and maximum execution time as
KPI tiles, and a new tile giving the average execution time scoped to
the selected range, labelled with that range so it cannot be confused
with the cumulative lifetime figure beside it; the existing tile is
relabelled "Mean Time (All Time)" for the same reason. The database
role that ran the query is shown beside the query text, falling back
to "Unknown" when it cannot be resolved.

The period-scoped average comes from a new GET /api/v1/metrics/query-
stats endpoint, computed as the sum of per-sample deltas rather than a
first-versus-last subtraction, so a pg_stat_reset() or restart part way
through the range costs a single interval instead of corrupting the
whole figure; it returns null rather than zero when no usable sample
pairs exist. The role name is resolved from pg_stat_activity via a
usesysid lookup mirroring the existing datid resolution, which only
works for roles observed with an active backend inside the retention
window.

This also fixes a pre-existing bug: the drill-down's execution-time and
call-count charts sent no query filter, so they aggregated across every
statement on the connection rather than the query being inspected.
/api/v1/metrics/query gains an optional `queryid` filter, which rejects
probes lacking that column rather than emitting invalid SQL.

Note one behaviour change beyond the issue: the database-name lookup
now picks the most recently observed name per OID instead of an
arbitrary one, so a database renamed within the retention window no
longer reports a name that can flip between requests.

Closes #350
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 77e46d84-9e4e-46fb-82df-af85bbca4a60

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 1 medium

Results:
1 new issue

Category Results
Complexity 1 medium

View in Codacy

🟢 Metrics 378 complexity · 45 duplication

Metric Results
Complexity 378
Duplication 45

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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.

1 participant