Files
openobserve/web/src/composables
Prabhat Sharma 8f60dbcc82 fix(metrics): widen rate windows when the scrape interval overstates cadence (#13576)
## Problem

Metrics explorer cards for histograms, counters, and summaries showed
**"Too few samples for a rate"** even though the streams had data. The
rate window is sized from the org's configured `scrape_interval` (e.g.
15s → `[1m]`), but when data actually arrives less often (the OTel demo
app exports every 60s), `rate()` almost never finds the two samples it
needs — so every rate-based card rendered the sparse message while
gauges charted fine.

Reproduced against a live instance:
`sum(rate(app_cart_add_item_latency_count[1m]))` → empty; the same query
with `[4m]` → `0.172/s`.

## Fix

**Widened-window retry** (`useMetricsExplorerGrid.ts`,
`computeWidenedRateWindows` in `metricDefaults.ts`): when a rate-based
card comes back empty but the presence probe confirms samples exist in
the window, retry with geometrically wider windows — 4×, then 16× the
standard window, capped at half the range — and chart the first rung
that answers. The sparse message now only appears when no honest window
could produce a chart.

**Editor / dashboard handoff** (`MetricsExplorer.vue`): the drill-in
normally hands the editor `$__rate_interval`, which resolves from the
same overstated scrape interval — opening a blank editor for a metric
the card visibly charts. The preview now remembers which rung worked
(`widenedRateWindow`, persisted through the card cache like
`nanGuardApplied`), and both the card→editor drill-in and the
favorites→dashboard conversion hand over that concrete window instead.
Cards that never needed widening keep the adaptive `$__rate_interval`
behavior.

Supporting changes:
- `previewKeysOf` enumerates the widened query keys so refresh
invalidates them instead of replaying stale retries from the queue
cache.
- Persisted-cache identity gains a shape version (`v: 2`) so pre-field
entries (widened data with no memory of the window) miss once and
re-learn live.
- A failing widened retry settles for the sparse answer already in hand
rather than repainting the card as an error; cancellations still abort.
- During a refresh the loading state carries `widenedRateWindow`
alongside the old results it keeps on screen, so a mid-refresh drill-in
stays correct.

## Verification

- Unit tests: retry ladder math (caps, dedup, no-room-to-widen), first-
and second-rung success, all-rungs-fail keeps the sparse card, window
carried on the preview, handoff passes the concrete window vs
`$__rate_interval` — 182 tests across the four spec files pass; ESLint
and vue-tsc clean.
- Live against a dev backend: previously-sparse `app_cart_*` cards all
render (network log shows `[1m]` → empty, presence probe, `[4m]` →
data); drill-in opens the editor seeded with `sum(rate(...[4m]))` and a
rendered chart, from both the live-query and cache-restored paths.
2026-07-31 19:45:26 +00:00
..
2026-07-28 07:58:21 +00:00