Skip to content

fix: first_over_time and last_over_time with unwrap under an aggregation read each series' sample from VictoriaLogs row_min and row_max instead of a stats function it lacks - #728

Merged
szibis merged 3 commits into
mainfrom
fix/unwrap-first-last-aggregation
Oct 22, 2026
Merged

szibis merged 3 commits into
mainfrom
fix/unwrap-first-last-aggregation

Conversation

@szibis

@szibis szibis commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Gap semantics/unwrap-first-last-under-aggregation. Loki 3.7.7 answers one series for sum(first_over_time({app="payment-service"} | logfmt | unwrap amount [5m])), and likewise for last_over_time. The proxy sent VictoriaLogs a stats first(...) / last(...); VictoriaLogs has neither function, so the proxy answered 422 on query_range and query. The same 422 happened under avg/min/max/count, with by (...), as a topk/bottomk inner, as a binary operand, and for the bare form without a parser.

Fix (VictoriaLogs does all of it, in one stats query). The query keeps each series' sample with row_min/row_max on _time, unpacks it to a number, then applies the outer aggregation:

stats by (<series>) row_min|row_max(_time, __lvp_v) as __lvp_inner | unpack_json from __lvp_inner fields (__lvp_v) | math __lvp_v as __lvp_inner | stats [by (...)] <agg>(__lvp_inner)

Remaining differences (already registered):

  • On query_range, values are step buckets rather than the window (semantics/unwrap-over-time-range-windows).
  • After a parser, series identity is (_stream, _msg) (semantics/unwrap-per-series-identity-raw-rows).
  • With equal timestamps, row_max keeps the first row where Loki keeps the later one.

Tests

  • Translator: TestFirstLastOverTimeUnderAggregationTranslatesToRowStats (12 shapes), TestFirstLastOverTimeBareIsOneValuePerSeries, TestFirstLastOverTimeUnsupportedGroupedAggregationFailsLoudly.
  • Proxy differentials vs a Loki-semantics reference (VictoriaLogs v1.49.0, v1.52.0, default; parsers none/logfmt/json): instant values, topk/bottomk, offset, range.
  • Conversion-error rows in TestUnwrapCountingQuery and TestUnwrapConversionErrorAnswersLokiText.
  • e2e vs Loki: TestCompat_UnwrapFirstLastUnderAggregation, TestCompat_UnwrapFirstLastTopkBottomk.

Rebased on main

Rebased onto main after the VictoriaLogs v1.49.0 floor (#770) and the sum without fold (#739); the open question about row_min(_time, …) before v1.43 no longer applies, since every supported version has it. #739's pinned tests pass unchanged. On main the new tests fail (406 subtests: the proxy sends last(...), which VictoriaLogs lacks, and answers 502); on this branch they pass. sum|max|min|avg|count without (pod) (first_over_time|last_over_time(... | unwrap ...)) now goes through the without fold where main answered 422; after a bare parser it carries the series identity of the open row semantics/unwrap-per-series-identity-raw-rows.

semantics/first-last-over-time-translation stays open: both of its requests now translate to the row_max chain, but its offset and |~ shapes have no committed test and its comparison against Loki has not run.

Proofs in progress

  • e2e against Loki on VictoriaLogs v1.49.0 and v1.52.0.
  • A/B at 1h/6h/24h/7d plus the control set, real Grafana range matrix with the fix proof, benchstat and the backend-safety load test.

Rebased onto main (2026-10-22)

Base moved from 8d57747b (v2.19.0) to 304b5549 (v2.25.1 plus #827). This PR is not stacked on #727 (its branch had main as the merge base), so it is rebased on origin/main alone. Head 8b338f04, three commits, all signed, subjects unchanged.

Conflict Resolution
CHANGELOG.md Rebuilt from main: this PR's entry is the only content of ## [Unreleased] / ### Fixed.
bench/visual/spec.json (same append point as #731's explore-unwrap-quantile-over-time) Kept both entries.
conformance/registry/generated/wiring.json, conformance/reports/{gaps,parity-gaps,roadmap}.md Took main's and regenerated with the repo generators; folded into the "record #728 as the fix" commit.
Go (translator.go, unwrap_conversion_error.go and tests) No textual conflicts; the unwrap conversion-error counter and the translator changes of main since v2.19.0 compose with the unpack_json allowance.

Gates (phase 1, no Docker, capped GOMEMLIMIT=3GiB GOMAXPROCS=4)

  • gofmt -l, go build ./..., go vet ./... and go vet ./test/e2e-compat/... and go vet -tags=e2e ./test/e2e-compat/... (the e2e files carry //go:build e2e; compile only, nothing run): clean.
  • go test -short -count=1 -p 1 ./... (all packages, 98 s, peak RSS 1.70 GB with /usr/bin/time -l, not compared with main in this phase) and the ./internal/... -json run that feeds the conformance gate: all ok.
  • go test -count=1 -run 'TestSlidingWindowStats_|TestOrderedJSONExtractedMetricDifferential' ./internal/proxy without -short (the tests that skip under -short and declare the registry items near this change; CI's evidence step runs without -short): ok.
  • -race on the touched tests: TestFirstLastOverTime*, TestUnwrapCountingQuery, TestUnwrapConversionErrorAnswersLokiText, TestUngroupedSumUnwrapDifferential, TestMatrix_MetricFunctions_AllSupported ok (478 tests, internal/proxy and internal/translator).
  • python3 scripts/ci/check_conformance.py --go-results <unit json>: ok (422 tests declare 138 items, 134 with a passing run, 0 failing).
  • python3 -m unittest discover -s scripts/ci/tests -p 'test_*.py': 181 tests OK. Harness tests (bench/ab, bench/visual, bench/parity): OK.
  • python3 scripts/ci/check_changelog_pr.py --base origin/main --head HEAD: ok. go run ./cmd/configdoc -check: ok.

Overlaps. With #727 and #730 the conflicts are textual only: CHANGELOG.md, bench/visual/spec.json, generated files, and internal/proxy/unwrap_ungrouped_sum_differential_test.go against #730 (both add a pipe branch to the VictoriaLogs emulator at the same spot; keep both). Merged together in a scratch tree (727+728+730) the only failing test is the golden table of #727/#730.

Not in this PR. On query_range, first_over_time and last_over_time still answer every point one step early and omit the sample at end (the bucket labelling that #727 fixes for sum, avg, min and max). It is outside this PR's scope and stays a follow-up.

Proofs to be refreshed (phase 2, need the stack)

Supported VictoriaLogs for the e2e runs: the floor v1.49.0 and the newest v1.53.0, with the CI pin v1.52.0 (the PR text from before the floor moved named older lines). Commands run from the worktree $SCRATCH/wt-728 on the PR head; the Colima VM colima-lvp is the Docker host (DOCKER_CONTEXT=colima-lvp), and the shared e2e stack must not be running while a fresh stack is started on the same ports.

1. e2e vs Loki (one fresh stack per group and per VictoriaLogs version)

docker --context colima-lvp build -t loki-vl-proxy:e2e-pr728 .
for V in v1.49.0 v1.52.0 v1.53.0; do
  ( cd test/e2e-compat && DOCKER_CONTEXT=colima-lvp PROXY_IMAGE=loki-vl-proxy:e2e-pr728 \
      VICTORIALOGS_IMAGE=victoriametrics/victoria-logs:$V docker compose up -d --no-build \
    && ../../scripts/ci/wait_e2e_stack.sh 180 )
  # this PR's tests (they ingest their own fixtures and wait for Loki; no TestSetup needed)
  go test -v -tags=e2e -timeout=600s -count=1 -run '^(TestCompat_UnwrapFirstLastUnderAggregation|TestCompat_UnwrapFirstLastTopkBottomk|TestCompat_UnwrapFirstLastRangeLevelBy)$' ./test/e2e-compat/
  ( cd test/e2e-compat && DOCKER_CONTEXT=colima-lvp docker compose down -v )
done

Then the two CI groups that cover the touched code, each on its own fresh stack on v1.52.0 and v1.49.0 (same up/down lines, -run pattern copied from .github/workflows/ci.yaml):

go test -v -tags=e2e -timeout=600s -count=1 -run '^(TestSetup_IngestLogs|TestCompat_.*|TestExtended_.*|TestChaining_.*|TestAlertingCompat_.*|TestExplore_HTTPQueryRangeContracts|TestLokiFunctions_.*|TestGrafanaDatasourceCatalogAndHealth|TestProxyCompatibilitySurface|TestPinnedCompatibilityMatrixMatchesCompose)$' ./test/e2e-compat/
go test -v -tags=e2e -timeout=600s -count=1 -run '^(TestSetup_IngestLogs|TestQuerySemanticsMatrixManifest|TestQuerySemanticsOperationsInventory|TestQuerySemanticsMatrix|TestGrafanaClickout_.*|TestMissingOps_.*|TestRangeMetricCompatibility.*|TestLogQL_Exhaustive_.*|TestPipeline_.*|TestEdge_DropErrorInstantQueryReturnsAggregatedResult|TestEdge_DetectedFieldsAfterJsonDropPipelineIncludesJsonFields)$' ./test/e2e-compat/

2. A/B proof (previous release / base vs PR vs Loki, own compose project and ports)

python3 bench/ab/pr_smoke.py --base origin/main --out $SCRATCH/ab-728 --loki-mem 3g --vl-mem 4g --project ab728 --ranges 1h,6h,24h --runs 5 --refresh-s 60 --refresh-runs 5
# sets the selection names for this change: control, drilldown-breakdown-exact, extracted-pushdown, extracted-suffix, json-filter-pushdown, loki-profile-otel-metadata, metric-latency-gap, parenthesized-range-or-filters, pattern-line-filter, pattern-line-filter-anchoring, plain-name-after-parser, unwrap-conversion-error, unwrap-sum-without, unwrap-ungrouped-sum, unwrap-validity
# a 7d pass and the control set explicitly (perf_matrix.py --set <set> --ranges 1h,6h,24h,7d --runs 5 --target main=... --target branch=... --target loki=... --out raw.json;
#   python3 bench/ab/report.py summarize raw.json --baseline main --candidate branch --label pr728-<set> --save bench/ab/results/)
python3 bench/ab/pr_smoke.py --same-build --out $SCRATCH/ab-728-aa --project ab728a    # noise floor

Plus go test -run '^$' -bench <touched benchmarks> -benchmem -count=6 ./internal/translator ./internal/proxy on origin/main and the head, compared with benchstat, and the backend-safety load test (many 24h/7d queries concurrently, VictoriaLogs RestartCount before and after, /labels probe answering 200).

3. Visual proof (isolated stack, base | PR | Loki)

python3 bench/visual/plan.py --base origin/main --out $SCRATCH/vs728/plan.json
python3 bench/visual/ci_run.py --base origin/main --plan $SCRATCH/vs728/plan.json --out $SCRATCH/vs728 --project vs728 --port-offset 200 --hours 24
python3 bench/visual/visual_comment.py --out $SCRATCH/vs728 --mode artifact --md $SCRATCH/vs728/comment.md

Plan: explore-unwrap-first-last-under-sum at 15m/1h/6h (the fix proof, fixes: semantics/unwrap-first-last-under-aggregation), the core set and the changed-file entries (37 captures; the plan trims the over-budget ones and drops explore-sum-without-count, explore-topk-sum-without — raise --max-captures or run those two by hand if wanted).

4. Real Grafana range matrix: the shapes below through the Loki-type datasources of the proxy and of Loki direct, over 5m, 15m, 1h, 6h, 24h and 7d where the data exists, compared for status, errors, series counts and totals.

Matrix shapes: sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap amount [$__auto])), the same with first_over_time, with avg/min/max/count, by (app), as a topk/bottomk inner and under a binary operation.

@github-actions github-actions Bot added size/XL Extra large change scope/translator LogQL translator scope/proxy Proxy core scope/docs Documentation scope/tests Tests bugfix Bug fix labels Oct 12, 2026
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

❌ Visual smoke: failed

Base 1c79dd35d2 vs PR e070299396, Grafana through the proxy builds and Loki on one fresh stack; run.
Loaded again, once and more patiently, after a first-pass difference or an unsettled page: explore-unwrap-first-last-under-sum 15m, explore-unwrap-first-last-under-sum 1h, explore-unwrap-first-last-under-sum 6h.
Core set: 5 capture(s) at 1h. Detailed set: 29 entries (explore-unwrap-first-last-under-sum, explore-metric-plain, explore-A, explore-B, explore-C, explore-E, explore-F, explore-logs-json, ...). 37 capture(s), 15m/1h/6h, 24h and 7d stay out of PR runs.
Trimmed to the 1h range for the capture budget: explore-A, explore-B, explore-C, explore-E, explore-F, explore-logs-json, explore-logfmt-metric, explore-logs-extracted, explore-extracted-metric, explore-extracted-filter-metric, explore-extracted-group-metric, explore-logs-plain-level, explore-plain-level-metric, explore-logs-line-filter-or, explore-metric-line-filter-or, explore-unwrap-sum, explore-unwrap-unit-string, explore-unwrap-missing-label, explore-unwrap-conversion-error, explore-unwrap-rate-sum, explore-empty-pattern-filter, explore-pattern-filter-anchored, explore-unwrap-quantile-over-time, explore-json-error-filter-metric, dd-field-service_version, dd-field-pipeline, explore-sum-without-rate, explore-topk-sum-without, explore-sum-without-count.
Not run (capture budget): explore-sum-without-count, explore-topk-sum-without, explore-sum-without-rate.

Fix proof

Captures of the exact cases this pull request adds or fixes (registry case, base | PR | Loki). The verdict compares the PR with Loki where the base did not match. The gate fails a case unless one capture is fixed or improved, or, beyond the Loki data window, the base failed where Loki and the PR both answered with data (the label does not excuse it; only visual: none on the case does).

semantics/unwrap-first-last-under-aggregation: ❌ still differs

page range base = PR (data) vs Loki (PR) verdict
explore-unwrap-first-last-under-sum 15m differs (1) 2 difference(s), 1 on base too, 1 new ❌ still differs
explore-unwrap-first-last-under-sum 1h differs (1) 2 difference(s), 1 on base too, 1 new ❌ still differs
explore-unwrap-first-last-under-sum 6h differs (1) n/a (beyond the Loki window) ⚪ undecided
explore-unwrap-first-last-under-sum-15m: still differs

explore-unwrap-first-last-under-sum-15m

explore-unwrap-first-last-under-sum-1h: still differs

explore-unwrap-first-last-under-sum-1h

explore-unwrap-first-last-under-sum-6h: undecided

explore-unwrap-first-last-under-sum-6h

Regression check

page range set base = PR (data) vs Loki (PR) pixel diff result
dd-fields 1h core ✅ identical identical (4 explained, 1 history-dependent) 0.11% ✅
dd-landing 1h core ✅ identical identical (3 explained) 0.14% ✅
dd-service-logs 1h core ✅ identical identical (3 explained, 1 history-dependent) 0.11% ✅
explore-logs-plain 1h core ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-metric-plain 1h core ✅ identical 1 difference(s), 1 on base too 0.04% ✅
dd-field-pipeline 1h detailed ✅ identical identical (3 explained, 1 history-dependent) 0.11% ✅
dd-field-service_version 1h detailed ✅ identical identical (3 explained, 1 history-dependent) 0.11% ✅
explore-A 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-B 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-C 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-E 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-F 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-empty-pattern-filter 1h detailed ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-extracted-filter-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-extracted-group-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-extracted-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-json-error-filter-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-logfmt-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-logs-extracted 1h detailed ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-logs-json 1h detailed ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-logs-line-filter-or 1h detailed ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-logs-plain-level 1h detailed ✅ identical 1 difference(s), 1 on base too; 1 explained 0.07% ✅
explore-metric-line-filter-or 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-metric-plain 15m detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-metric-plain 6h detailed ✅ identical n/a (beyond the Loki window) 0.04% ✅
explore-pattern-filter-anchored 1h detailed ✅ identical 1 difference(s), 1 on base too 0.07% ✅
explore-plain-level-metric 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-conversion-error 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-first-last-under-sum 15m detailed differs (1): query ('sum by (service_name) (last_over_time({service_name= 2 difference(s), 1 on base too, 1 new 0.99% ❌ data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if int
explore-unwrap-first-last-under-sum 1h detailed differs (1): query ('sum by (service_name) (last_over_time({service_name= 2 difference(s), 1 on base too, 1 new 1.50% ❌ data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if int
explore-unwrap-first-last-under-sum 6h detailed differs (1): query ('sum by (service_name) (last_over_time({service_name= n/a (beyond the Loki window) 4.56% ❌ data differs base vs PR and no Loki data for this range; label the pull request `visual-change-expected` if in
explore-unwrap-missing-label 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-quantile-over-time 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-rate-sum 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-sum 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
explore-unwrap-unit-string 1h detailed ✅ identical 1 difference(s), 1 on base too 0.04% ✅
tail-json-filter live detailed ✅ identical entries in the window: PR 1753, Loki 254, in both 254 6.28% ✅

Gate: a base-vs-PR data difference passes when the PR is closer to Loki, and fails when the PR diverges from Loki or Loki cannot decide it (at a range Loki does not hold, a difference passes when the same page proved it closer to Loki at a shorter range; otherwise label the pull request visual-change-expected to accept an intended change). Also failing: a panel empty on the PR but not on the base, an error banner, panel error, error answer or new "No data" panel on the PR, a PR side that never settled, a difference that did not reproduce on the recapture. Pixel differences only warn.

explore-unwrap-first-last-under-sum-15m: data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if intended (1):
  • data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if intended (1): query ('sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap: series sets differ: 0 only left [], 1 only right ['(\'A\', \'\
  • vs Loki: query ('sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap: {"service_name": "payment-service"}: timestamps differ (90 vs 90 points)
  • vs Loki: resource /api/datasources/uid/*/resources/index/stats?query=%7Bservice_name%3D%22payment-service%22: body: content differs (rows 0 vs 0)

explore-unwrap-first-last-under-sum-15m

explore-unwrap-first-last-under-sum-1h: data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if intended (1):
  • data differs base vs PR and neither build matches Loki; label the pull request `visual-change-expected` if intended (1): query ('sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap: series sets differ: 0 only left [], 1 only right ['(\'A\', \'\
  • vs Loki: query ('sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap: {"service_name": "payment-service"}: timestamps differ (360 vs 360 points)
  • vs Loki: resource /api/datasources/uid/*/resources/index/stats?query=%7Bservice_name%3D%22payment-service%22: body: content differs (rows 0 vs 0)

explore-unwrap-first-last-under-sum-1h

explore-unwrap-first-last-under-sum-6h: data differs base vs PR and no Loki data for this range; label the pull request `visual-change-expected` if intended (1)
  • data differs base vs PR and no Loki data for this range; label the pull request `visual-change-expected` if intended (1): query ('sum by (service_name) (last_over_time({service_name="payment-service"} | logfmt | unwrap: series sets differ: 0 only left [], 1 only right ['(\'A\', \'\
  • pixel diff 4.6%

explore-unwrap-first-last-under-sum-6h

Core set montages (5): base | PR | Loki

dd-fields-1h

dd-fields-1h

dd-landing-1h

dd-landing-1h

dd-service-logs-1h

dd-service-logs-1h

explore-logs-plain-1h

explore-logs-plain-1h

explore-metric-plain-1h

explore-metric-plain-1h

All montages of this run: pr-visuals/pr-728.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

⚪ Performance A/B: no change beyond noise

119 shape×range — 119 ⚪ same · results vs Loki: 97 same, 0 new difference(s), 22 pre-existing

Every shape is within noise of the base build (±30% and 100 ms).

119 unchanged shape×range (within noise)
shape range base p50 PR p50 change Loki p50 PR ÷ Loki result vs Loki
⚪ bytes_over_time by app 1h 43 ms 43 ms ⚪ +0% 85 ms 0.51× ✅ same
⚪ drilldown service landing 1h 21 ms 18 ms ⚪ -14% 35 ms 0.51× ✅ same
⚪ instant json filtered instant 6 ms 6 ms ⚪ +0% 59 ms 0.10× ✅ same
⚪ instant json volume instant 19 ms 18 ms ⚪ -5% 74 ms 0.24× ✅ same
⚪ instant ungrouped rate instant 5 ms 5 ms ⚪ +0% 62 ms 0.08× ✅ same
⚪ json rate by level (no filter, no drop) 1h 400 400 ⚪ +0% 400 — ✅ same
⚪ json volume no filters 1h 112 ms 123 ms ⚪ +10% 72 ms 1.71× ✅ same
⚪ logfmt count by level, filter, drop 1h 255 ms 246 ms ⚪ -4% 52 ms 4.73× ✅ same
⚪ logfmt volume 1h 120 ms 122 ms ⚪ +2% 56 ms 2.18× ✅ same
⚪ logs plain 1h 46 ms 41 ms ⚪ -11% 39 ms 1.05× ✅ same
⚪ logs | json 1h 60 ms 53 ms ⚪ -12% 53 ms 1.00× ✅ same
⚪ logs | logfmt 1h 94 ms 109 ms ⚪ +16% 44 ms 2.48× ✅ same
⚪ stream-label count by app 1h 15 ms 16 ms ⚪ +7% 41 ms 0.39× ✅ same
⚪ topk rate by app 1h 33 ms 29 ms ⚪ -12% 70 ms 0.41× ➖ differs (as base)
⚪ ungrouped rate 1h 8 ms 8 ms ⚪ +0% 86 ms 0.09× ✅ same
⚪ DB3 json field breakdown user_id 1h 27 ms 30 ms ⚪ +11% 54 ms 0.56× ✅ same
⚪ DB4 json field breakdown batch_id 1h 66 ms 64 ms ⚪ -3% 56 ms 1.14× ✅ same
⚪ X1 json filter level_extracted, by level 1h 221 ms 216 ms ⚪ -2% 44 ms 4.91× ✅ same
⚪ X2 json group by level_extracted 1h 166 ms 172 ms ⚪ +4% 44 ms 3.91× ✅ same
⚪ X3 json rate, level_extracted equality 1h 147 ms 152 ms ⚪ +3% 39 ms 3.90× ✅ same
⚪ X4 json bytes, level_extracted regexp 1h 219 ms 217 ms ⚪ -1% 73 ms 2.97× ✅ same
⚪ X5 logfmt filter level_extracted, by level 1h 355 ms 366 ms ⚪ +3% 73 ms 5.01× ✅ same
⚪ E1 logs, json parser over stream labels 1h 83 ms 87 ms ⚪ +5% 46 ms 1.89× ✅ same
⚪ E2 logs, logfmt parser over stream labels 1h 54 ms 52 ms ⚪ -4% 34 ms 1.53× ✅ same
⚪ E3 logs, json, existence filter on level_extracted 1h 105 ms 110 ms ⚪ +5% 53 ms 2.08× ✅ same
⚪ E4 logs, logfmt, existence filter on level_extracted 1h 69 ms 72 ms ⚪ +4% 46 ms 1.57× ✅ same
⚪ E5 logs, json, drop level_extracted 1h 82 ms 88 ms ⚪ +7% 41 ms 2.15× ✅ same
⚪ E6 logfmt count by level_extracted 1h 28 ms 27 ms ⚪ -4% 7 ms 3.86× ✅ same
⚪ E7 json count by level_extracted 1h 84 ms 84 ms ⚪ +0% 16 ms 5.25× ✅ same
⚪ E8 instant logfmt by level_extracted instant 5 ms 5 ms ⚪ +0% 8 ms 0.62× ✅ same
⚪ J1 json no-error count by service_name, one service 1h 62 ms 62 ms ⚪ +0% 27 ms 2.30× ✅ same
⚪ J2 json no-error count by app, namespace 1h 165 ms 163 ms ⚪ -1% 82 ms 1.99× ✅ same
⚪ J3 json no-error count by parsed method 1h 81 ms 83 ms ⚪ +2% 22 ms 3.77× ✅ same
⚪ J4 json no-error count by service_name, all services 1h 183 ms 185 ms ⚪ +1% 83 ms 2.23× ✅ same
⚪ J5 json no-error bytes_rate by app 1h 151 ms 151 ms ⚪ +0% 61 ms 2.48× ✅ same
⚪ A explore volume, 2 filters, drop 1h 83 ms 84 ms ⚪ +1% 166 ms 0.51× ✅ same
⚪ B grouped sum, filter, no drop 1h 59 ms 57 ms ⚪ -3% 45 ms 1.27× ✅ same
⚪ C ungrouped sum, filter, no drop 1h 56 ms 56 ms ⚪ +0% 44 ms 1.27× ✅ same
⚪ D volume, no filters 1h 116 ms 114 ms ⚪ -2% 48 ms 2.38× ✅ same
⚪ E field breakdown pipeline (explore) 1h 58 ms 57 ms ⚪ -2% 43 ms 1.33× ✅ same
⚪ F field breakdown service_version (explore) 1h 78 ms 85 ms ⚪ +9% 52 ms 1.63× ✅ same
⚪ G field breakdown pipeline (drilldown) 1h 26 ms 25 ms ⚪ -4% 34 ms 0.74× ✅ same
⚪ H field breakdown service_version (drilldown) 1h 45 ms 45 ms ⚪ +0% 33 ms 1.36× ✅ same
⚪ I grafana volume of B 1h 56 ms 57 ms ⚪ +2% 39 ms 1.46× ✅ same
⚪ O2 explore log volume (Grafana form), underscore structured-metadata filter 1h 45 ms 46 ms ⚪ +2% 72 ms 0.64× ✅ same
⚪ DL1 drilldown field breakdown json-expr, level filter 1h 275 ms 269 ms ⚪ -2% 32 ms 8.41× ✅ same
⚪ DL2 drilldown field breakdown, level + stream-label filter before json 1h 28 ms 29 ms ⚪ +4% 8 ms 3.62× ✅ same
⚪ DL3 drilldown logfmt field breakdown, level filter 1h 354 ms 341 ms ⚪ -4% 84 ms 4.06× ➖ differs (as base)
⚪ DL4 instant count, level filter, json+logfmt, 1h instant 277 ms 275 ms ⚪ -1% 785 ms 0.35× ✅ sum ±0.31%
⚪ DL6 explore volume, level filter before json 1h 80 ms 79 ms ⚪ -1% 67 ms 1.18× ✅ same
⚪ OR1 logs, or alternatives 1h 58 ms 54 ms ⚪ -7% 56 ms 0.96× ✅ same
⚪ OR2 logs, negated or alternatives 1h 52 ms 48 ms ⚪ -8% 68 ms 0.71× ✅ same
⚪ OR3 logs, regexp or alternatives 1h 48 ms 41 ms ⚪ -15% 59 ms 0.69× ✅ same
⚪ OR4 count by level, or alternatives with parser 1h 47 ms 47 ms ⚪ +0% 41 ms 1.15× ✅ same
⚪ OR5 rate, negated regexp or alternatives 1h 35 ms 33 ms ⚪ -6% 78 ms 0.42× ✅ same
⚪ OR6 instant, or alternatives instant 5 ms 6 ms ⚪ +20% 66 ms 0.09× ✅ same
⚪ P1 api-gateway empty pattern 1h 15 ms 15 ms ⚪ +0% 14 ms 1.07× ✅ same
⚪ P2 api-gateway not empty pattern, line filter 1h 46 ms 44 ms ⚪ -4% 21 ms 2.10× ✅ same
⚪ P3 nginx count_over_time, pattern with spaces 1h 9 ms 9 ms ⚪ +0% 7 ms 1.29× ✅ same
⚪ P4 nginx count_over_time, GET request pattern 1h 11 ms 10 ms ⚪ -9% 5 ms 2.00× ✅ same
⚪ A1 nginx include GET, log query 1h 14 ms 15 ms ⚪ +7% 7 ms 2.14× ✅ same
⚪ A2 nginx exclude GET, log query 1h 26 ms 25 ms ⚪ -4% 8 ms 3.12× ✅ same
⚪ A3 nginx include GET, count_over_time 1h 10 ms 12 ms ⚪ +20% 5 ms 2.40× ✅ same
⚪ A4 nginx exclude GET, count_over_time 1h 12 ms 14 ms ⚪ +17% 6 ms 2.33× ✅ same
⚪ A5 drilldown exclude, volume by detected_level 1h 17 ms 18 ms ⚪ +6% 6 ms 3.00× ✅ same
⚪ A6 nginx include ends on a literal, log query 1h 11 ms 11 ms ⚪ +0% 4 ms 2.75× ✅ same
⚪ A7 nginx exclude ends on a literal, log query 1h 15 ms 14 ms ⚪ -7% 7 ms 2.00× ✅ same
⚪ A8 nginx include two literals, count_over_time 1h 14 ms 14 ms ⚪ +0% 5 ms 2.80× ✅ same
⚪ A9 nginx include two literals, ends on a literal, count_over_time 1h 14 ms 13 ms ⚪ -7% 5 ms 2.60× ✅ same
⚪ P1 logs, json, level equals 1h 87 ms 84 ms ⚪ -3% 61 ms 1.38× ✅ same
⚪ P2 logs, logfmt, level not equal 1h 19 ms 18 ms ⚪ -5% 7 ms 2.57× ✅ same
⚪ P3 logs, json, level existence 1h 94 ms 97 ms ⚪ +3% 60 ms 1.62× ✅ same
⚪ P4 logfmt count by level 1h 18 ms 18 ms ⚪ +0% 6 ms 3.00× ✅ same
⚪ P5 json count by level 1h 45 ms 47 ms ⚪ +4% 14 ms 3.36× ✅ same
⚪ P6 json count, level filter 1h 9 ms 9 ms ⚪ +0% 13 ms 0.69× ✅ same
⚪ P7 json rate by level, level regexp 1h 10 ms 10 ms ⚪ +0% 13 ms 0.77× ✅ same
⚪ P8 json count by a name that is no stream label 1h 48 ms 47 ms ⚪ -2% 13 ms 3.62× ✅ same
⚪ P9 instant logfmt by level instant 5 ms 5 ms ⚪ +0% 7 ms 0.71× ✅ same
⚪ E1 json duration_ms sum by service 1h 46 ms 45 ms ⚪ -2% 17 ms 2.65× ➖ differs (as base)
⚪ E2 json duration_ms p95 by service 1h 156 ms 163 ms ⚪ +4% 14 ms 12× ✅ same
⚪ E3 logfmt latency_ms rate, production 1h 266 ms 267 ms ⚪ +0% 98 ms 2.72× ➖ differs (as base)
⚪ E4 logfmt size_bytes max by service 1h 26 ms 26 ms ⚪ +0% 10 ms 2.60× ➖ differs (as base)
⚪ E5 json duration_ms sum, instant instant 18 ms 18 ms ⚪ +0% 20 ms 0.90× ✅ same
⚪ E6 logfmt ttl unit string (Loki 400) 1h 400 400 ⚪ -3% 400 — ✅ same
⚪ E7 json hexadecimal trace_id (Loki 400) 1h 400 400 ⚪ +3% 400 — ✅ same
⚪ E8 json duration_ms sum by service, namespace prod 1h 101 ms 104 ms ⚪ +3% 77 ms 1.35× ➖ differs (as base)
⚪ E9 logfmt latency_ms sum by service, namespace prod 1h 168 ms 165 ms ⚪ -2% 66 ms 2.50× ➖ differs (as base)
⚪ W1 sum without pod, max_over_time 1h 28 ms 26 ms ⚪ -7% 16 ms 1.62× ➖ differs (as base)
⚪ W2 sum without pod, sum_over_time 1h 26 ms 26 ms ⚪ +0% 15 ms 1.73× ➖ differs (as base)
⚪ W3 sum without pod, rate 1h 76 ms 76 ms ⚪ +0% 13 ms 5.85× ✅ same
⚪ W4 max without pod, max_over_time 1h 29 ms 28 ms ⚪ -3% 13 ms 2.15× ➖ differs (as base)
⚪ W5 sum without pod, max_over_time, instant instant 8 ms 6 ms ⚪ -25% 12 ms 0.50× ✅ same
⚪ W6 sum without pod, rate, instant instant 8 ms 11 ms ⚪ +37% 13 ms 0.85× ✅ same
⚪ W7 topk 5 of sum without pod 1h 28 ms 27 ms ⚪ -4% 13 ms 2.08× ➖ differs (as base)
⚪ W8 sum without pod, count_over_time (production) 1h 527 ms 580 ms ⚪ +10% 0 — ➖ differs (as base)
⚪ W9 label_replace control, instant instant 4 ms 5 ms ⚪ +25% 66 ms 0.08× ✅ same
⚪ U1 logfmt amount rate 1h 20 ms 22 ms ⚪ +10% 12 ms 1.83× ✅ same
⚪ U2 json duration_ms rate 1h 47 ms 46 ms ⚪ -2% 22 ms 2.09× ✅ same
⚪ U3 json duration_ms rate, error filter 1h 47 ms 49 ms ⚪ +4% 20 ms 2.45× ✅ same
⚪ U4 logfmt latency_ms rate, production 1h 194 ms 188 ms ⚪ -3% 90 ms 2.09× ➖ differs (as base)
⚪ U5 logfmt amount rate, instant instant 6 ms 5 ms ⚪ -17% 10 ms 0.50× ✅ same
⚪ U6 json duration_ms rate, instant instant 7 ms 9 ms ⚪ +29% 18 ms 0.50× ✅ same
⚪ U7 json duration_ms sum_over_time, instant instant 8 ms 9 ms ⚪ +12% 17 ms 0.53× ✅ same
⚪ U8 logfmt amount rate by service (grouped) 1h 23 ms 23 ms ⚪ +0% 10 ms 2.30× ✅ same
⚪ U9 logfmt amount rate_counter (folded per series) 1h 158 ms 145 ms ⚪ -8% 25 ms 5.80× ➖ differs (as base)
⚪ U1 json duration_ms sum by service 1h 46 ms 46 ms ⚪ +0% 18 ms 2.56× ➖ differs (as base)
⚪ U10 instant sum_over_time unwrap instant 19 ms 17 ms ⚪ -11% 20 ms 0.85× ✅ same
⚪ U11 instant max_over_time missing label instant 5 ms 5 ms ⚪ +0% 14 ms 0.36× ✅ same
⚪ U12 json duration_ms over every service 1h 129 ms 123 ms ⚪ -5% 45 ms 2.73× ➖ differs (as base)
⚪ U13 logfmt latency_ms over every service 1h 282 ms 286 ms ⚪ +1% 56 ms 5.11× ➖ differs (as base)
⚪ U14 duration() of a unit string 1h 24 ms 25 ms ⚪ +4% 6 ms 4.17× ➖ differs (as base)
⚪ U2 json duration_ms max by service 1h 51 ms 51 ms ⚪ +0% 32 ms 1.59× ➖ differs (as base)
⚪ U3 json duration_ms sliding sum 1h 47 ms 46 ms ⚪ -2% 26 ms 1.77× ➖ differs (as base)
⚪ U4 logfmt size_bytes sum by service 1h 22 ms 22 ms ⚪ +0% 7 ms 3.14× ➖ differs (as base)
⚪ U5 logfmt ttl unit string (no sample) 1h 22 ms 22 ms ⚪ +0% 6 ms 3.67× ✅ same
⚪ U6 missing label, no parser 1h 13 ms 13 ms ⚪ +0% 10 ms 1.30× ✅ same
⚪ U7 missing label, ungrouped sum 1h 12 ms 12 ms ⚪ +0% 10 ms 1.20× ✅ same
⚪ U8 rate of an unwrapped label 1h 47 ms 45 ms ⚪ -4% 13 ms 3.46× ✅ same
⚪ U9 bytes() conversion 1h 29 ms 28 ms ⚪ -3% 9 ms 3.11× ➖ differs (as base)
Cold (first-run) timings — what a user opening a panel sees
shape range base cold PR cold Loki cold PR ÷ Loki cold
bytes_over_time by app 1h 40 ms 39 ms 416 ms 0.09×
drilldown service landing 1h 20 ms 22 ms 363 ms 0.06×
instant json filtered instant 6 ms 6 ms 59 ms 0.10×
instant json volume instant 18 ms 17 ms 71 ms 0.24×
instant ungrouped rate instant 18 ms 7 ms 59 ms 0.12×
json rate by level (no filter, no drop) 1h 400 400 400 —
json volume no filters 1h 113 ms 112 ms 559 ms ↺ 0.20×
logfmt count by level, filter, drop 1h 245 ms 244 ms 548 ms 0.45×
logfmt volume 1h 131 ms 117 ms 645 ms 0.18×
logs plain 1h 53 ms 51 ms 64 ms 0.80×
logs | json 1h 62 ms 67 ms 51 ms 1.31×
logs | logfmt 1h 87 ms 108 ms 45 ms 2.40×
stream-label count by app 1h 15 ms 15 ms 397 ms 0.04×
topk rate by app 1h 38 ms 26 ms 433 ms 0.06×
ungrouped rate 1h 8 ms 8 ms 393 ms 0.02×
DB3 json field breakdown user_id 1h 34 ms 27 ms 493 ms 0.05×
DB4 json field breakdown batch_id 1h 56 ms 78 ms 515 ms 0.15×
X1 json filter level_extracted, by level 1h 1.95 s 1.92 s 657 ms 2.93×
X2 json group by level_extracted 1h 164 ms 168 ms 638 ms 0.26×
X3 json rate, level_extracted equality 1h 144 ms 155 ms 454 ms 0.34×
X4 json bytes, level_extracted regexp 1h 214 ms 205 ms 499 ms 0.41×
X5 logfmt filter level_extracted, by level 1h 363 ms 355 ms 653 ms 0.54×
E1 logs, json parser over stream labels 1h 119 ms 114 ms 57 ms 2.00×
E2 logs, logfmt parser over stream labels 1h 47 ms 45 ms 37 ms 1.22×
E3 logs, json, existence filter on level_extracted 1h 103 ms 107 ms 94 ms 1.14×
E4 logs, logfmt, existence filter on level_extracted 1h 70 ms 74 ms 58 ms 1.28×
E5 logs, json, drop level_extracted 1h 98 ms 85 ms 45 ms 1.89×
E6 logfmt count by level_extracted 1h 29 ms 28 ms 30 ms 0.93×
E7 json count by level_extracted 1h 798 ms 795 ms 175 ms 4.54×
E8 instant logfmt by level_extracted instant 5 ms 5 ms 8 ms 0.62×
J1 json no-error count by service_name, one service 1h 133 ms 128 ms 135 ms 0.95×
J2 json no-error count by app, namespace 1h 241 ms 235 ms 424 ms 0.55×
J3 json no-error count by parsed method 1h 87 ms 83 ms 118 ms 0.70×
J4 json no-error count by service_name, all services 1h 291 ms 283 ms 552 ms 0.51×
J5 json no-error bytes_rate by app 1h 150 ms 150 ms 385 ms 0.39×
A explore volume, 2 filters, drop 1h 1.32 s 801 ms 896 ms 0.89×
B grouped sum, filter, no drop 1h 83 ms 73 ms 395 ms 0.18×
C ungrouped sum, filter, no drop 1h 68 ms 70 ms 387 ms 0.18×
D volume, no filters 1h 110 ms 110 ms 559 ms 0.20×
E field breakdown pipeline (explore) 1h 61 ms 60 ms 381 ms 0.16×
F field breakdown service_version (explore) 1h 731 ms 760 ms 431 ms 1.76×
G field breakdown pipeline (drilldown) 1h 26 ms 26 ms 369 ms 0.07×
H field breakdown service_version (drilldown) 1h 65 ms 85 ms 448 ms 0.19×
I grafana volume of B 1h 68 ms 65 ms 412 ms 0.16×
O2 explore log volume (Grafana form), underscore structured-metadata filter 1h 105 ms 99 ms 524 ms 0.19×
DL1 drilldown field breakdown json-expr, level filter 1h 285 ms 261 ms 299 ms 0.87×
DL2 drilldown field breakdown, level + stream-label filter before json 1h 40 ms 30 ms 20 ms 1.50×
DL3 drilldown logfmt field breakdown, level filter 1h 358 ms 368 ms 641 ms 0.57×
DL4 instant count, level filter, json+logfmt, 1h instant 276 ms 284 ms 799 ms 0.36×
DL6 explore volume, level filter before json 1h 127 ms 113 ms 502 ms 0.23×
OR1 logs, or alternatives 1h 57 ms 57 ms 90 ms 0.63×
OR2 logs, negated or alternatives 1h 51 ms 48 ms 43 ms 1.12×
OR3 logs, regexp or alternatives 1h 41 ms 41 ms 58 ms 0.71×
OR4 count by level, or alternatives with parser 1h 85 ms 78 ms 335 ms 0.23×
OR5 rate, negated regexp or alternatives 1h 39 ms 35 ms 402 ms 0.09×
OR6 instant, or alternatives instant 6 ms 6 ms 58 ms 0.10×
P1 api-gateway empty pattern 1h 21 ms 16 ms 55 ms 0.29×
P2 api-gateway not empty pattern, line filter 1h 50 ms 48 ms 22 ms 2.18×
P3 nginx count_over_time, pattern with spaces 1h 10 ms 9 ms 16 ms 0.56×
P4 nginx count_over_time, GET request pattern 1h 24 ms 29 ms 37 ms 0.78×
A1 nginx include GET, log query 1h 21 ms 16 ms 7 ms 2.29×
A2 nginx exclude GET, log query 1h 25 ms 25 ms 8 ms 3.12×
A3 nginx include GET, count_over_time 1h 11 ms 10 ms 37 ms ↺ 0.27×
A4 nginx exclude GET, count_over_time 1h 12 ms 12 ms 25 ms 0.48×
A5 drilldown exclude, volume by detected_level 1h 26 ms 25 ms 22 ms 1.14×
A6 nginx include ends on a literal, log query 1h 10 ms 11 ms 16 ms 0.69×
A7 nginx exclude ends on a literal, log query 1h 17 ms 14 ms 9 ms 1.56×
A8 nginx include two literals, count_over_time 1h 15 ms 16 ms 20 ms 0.80×
A9 nginx include two literals, ends on a literal, count_over_time 1h 13 ms 13 ms 21 ms 0.62×
P1 logs, json, level equals 1h 90 ms 84 ms 64 ms 1.31×
P2 logs, logfmt, level not equal 1h 18 ms 19 ms 26 ms 0.73×
P3 logs, json, level existence 1h 114 ms 100 ms 55 ms 1.82×
P4 logfmt count by level 1h 19 ms 18 ms 28 ms 0.64×
P5 json count by level 1h 50 ms 46 ms 104 ms 0.44×
P6 json count, level filter 1h 10 ms 9 ms 114 ms 0.08×
P7 json rate by level, level regexp 1h 10 ms 10 ms 101 ms 0.10×
P8 json count by a name that is no stream label 1h 54 ms 54 ms 94 ms 0.57×
P9 instant logfmt by level instant 4 ms 5 ms 7 ms 0.71×
E1 json duration_ms sum by service 1h 51 ms 46 ms 99 ms 0.46×
E2 json duration_ms p95 by service 1h 147 ms 165 ms 105 ms 1.57×
E3 logfmt latency_ms rate, production 1h 283 ms 271 ms 561 ms 0.48×
E4 logfmt size_bytes max by service 1h 25 ms 24 ms 107 ms 0.22×
E5 json duration_ms sum, instant instant 22 ms 24 ms 20 ms 1.20×
E6 logfmt ttl unit string (Loki 400) 1h 400 400 400 —
E7 json hexadecimal trace_id (Loki 400) 1h 400 400 400 —
E8 json duration_ms sum by service, namespace prod 1h 111 ms 114 ms 445 ms 0.26×
E9 logfmt latency_ms sum by service, namespace prod 1h 168 ms 173 ms 463 ms 0.37×
W1 sum without pod, max_over_time 1h 37 ms 30 ms 77 ms 0.39×
W2 sum without pod, sum_over_time 1h 28 ms 29 ms 62 ms 0.47×
W3 sum without pod, rate 1h 80 ms 76 ms 62 ms 1.23×
W4 max without pod, max_over_time 1h 27 ms 30 ms 73 ms 0.41×
W5 sum without pod, max_over_time, instant instant 8 ms 7 ms 12 ms 0.58×
W6 sum without pod, rate, instant instant 8 ms 9 ms 11 ms 0.82×
W7 topk 5 of sum without pod 1h 31 ms 27 ms 78 ms 0.35×
W8 sum without pod, count_over_time (production) 1h 548 ms 552 ms 0 —
W9 label_replace control, instant instant 7 ms 6 ms 66 ms 0.09×
U1 logfmt amount rate 1h 26 ms 24 ms 30 ms 0.80×
U2 json duration_ms rate 1h 47 ms 49 ms 80 ms 0.61×
U3 json duration_ms rate, error filter 1h 47 ms 47 ms 87 ms 0.54×
U4 logfmt latency_ms rate, production 1h 189 ms 187 ms 553 ms 0.34×
U5 logfmt amount rate, instant instant 5 ms 5 ms 9 ms 0.56×
U6 json duration_ms rate, instant instant 8 ms 7 ms 17 ms 0.41×
U7 json duration_ms sum_over_time, instant instant 11 ms 8 ms 17 ms 0.47×
U8 logfmt amount rate by service (grouped) 1h 30 ms 24 ms 37 ms 0.65×
U9 logfmt amount rate_counter (folded per series) 1h 154 ms 144 ms 166 ms 0.87×
U1 json duration_ms sum by service 1h 49 ms 43 ms 146 ms 0.29×
U10 instant sum_over_time unwrap instant 20 ms 22 ms 21 ms 1.05×
U11 instant max_over_time missing label instant 5 ms 4 ms 13 ms 0.31×
U12 json duration_ms over every service 1h 134 ms 125 ms 568 ms 0.22×
U13 logfmt latency_ms over every service 1h 276 ms 277 ms 832 ms 0.33×
U14 duration() of a unit string 1h 25 ms 26 ms 34 ms 0.76×
U2 json duration_ms max by service 1h 53 ms 55 ms 594 ms 0.09×
U3 json duration_ms sliding sum 1h 44 ms 45 ms 151 ms 0.30×
U4 logfmt size_bytes sum by service 1h 22 ms 21 ms 34 ms 0.62×
U5 logfmt ttl unit string (no sample) 1h 21 ms 22 ms 29 ms 0.76×
U6 missing label, no parser 1h 13 ms 13 ms 62 ms 0.21×
U7 missing label, ungrouped sum 1h 12 ms 12 ms 89 ms 0.13×
U8 rate of an unwrapped label 1h 45 ms 46 ms 140 ms 0.33×
U9 bytes() conversion 1h 34 ms 29 ms 34 ms 0.85×

↺ Loki cold taken from the first set that ran the same query; Loki's cache answered this one.

Why these shapes
  • internal/translator/translator.go → 117: control/bytes_over_time by app, control/instant json filtered, control/instant json volume, control/instant ungrouped rate, control/json rate by level (no filter, no drop), control/json volume no filters, control/logfmt count by level, filter, drop, control/logfmt volume …
  • internal/proxy/unwrap_conversion_error.go → 64: control/instant json filtered, control/instant json volume, control/json rate by level (no filter, no drop), control/json volume no filters, extracted-pushdown/X1 json filter level_extracted, by level, extracted-pushdown/X2 json group by level_extracted, extracted-pushdown/X3 json rate, level_extracted equality, extracted-pushdown/X4 json bytes, level_extracted regexp …
  • control smoke → 8: control/drilldown service landing, control/instant ungrouped rate, control/json rate by level (no filter, no drop), control/json volume no filters, control/logs plain, control/logs | json, control/stream-label count by app, control/topk rate by app

base 1c79dd35d2 → PR 94bf6ee337 · 4 runs (first is cold), warm p50 · ranges 1h · noise ±30% and 100 ms · VictoriaLogs restarts 0→0 · 17.2 min. Same runner, one fresh stack, targets interleaved per request. How to read and reproduce: bench/ab/README.md.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

PR Quality Report

Compared against base branch main.

Coverage and tests

Signal Base PR Delta
Test count 12218 12635 417
Coverage 88.4% 88.4% 0.0% (stable)

Compatibility

Track Base PR Delta
Loki API 100.0% 11/11 (100.0%) 0.0% (stable)
Logs Drilldown 100.0% 17/17 (100.0%) 0.0% (stable)
VictoriaLogs 100.0% 11/11 (100.0%) 0.0% (stable)

Performance smoke

Lower CPU cost (ns/op) is better. Lower benchmark memory cost (B/op, allocs/op) is better. Higher throughput is better. Lower load-test memory growth is better. Benchmark rows are medians from repeated samples.

Signal Base PR Delta
QueryRange cache-hit CPU cost 3426.0 ns/op 3442.0 ns/op +0.5% (stable)
QueryRange cache-hit memory 1240.0 B/op 1240.0 B/op 0.0% (stable)
QueryRange cache-hit allocations 27.0 allocs/op 27.0 allocs/op 0.0% (stable)
QueryRange cache-bypass CPU cost 4039.0 ns/op 4097.0 ns/op +1.4% (stable)
QueryRange cache-bypass memory 1303.0 B/op 1303.0 B/op 0.0% (stable)
QueryRange cache-bypass allocations 27.0 allocs/op 27.0 allocs/op 0.0% (stable)
Labels cache-hit CPU cost 908.7 ns/op 906.0 ns/op -0.3% (stable)
Labels cache-hit memory 48.0 B/op 48.0 B/op 0.0% (stable)
Labels cache-hit allocations 3.0 allocs/op 3.0 allocs/op 0.0% (stable)
Labels cache-bypass CPU cost 1493.0 ns/op 1494.0 ns/op +0.1% (stable)
Labels cache-bypass memory 400.0 B/op 400.0 B/op 0.0% (stable)
Labels cache-bypass allocations 14.0 allocs/op 14.0 allocs/op 0.0% (stable)

State

  • Coverage, compatibility, and sampled performance are reported here from the same PR workflow.
  • This is a delta report, not a release gate by itself. Required checks still decide merge safety.
  • Performance is a smoke comparison, not a full benchmark lab run.
  • Delta states use the same noise guards as the quality gate (percent + absolute + low-baseline checks), so report labels match merge-gate behavior.

szibis added a commit that referenced this pull request Oct 12, 2026
…-aggregation, with its visual fix proof page
@github-actions github-actions Bot added size/XL Extra large change and removed size/XL Extra large change labels Oct 12, 2026
szibis added a commit that referenced this pull request Oct 12, 2026
…-aggregation, with its visual fix proof page
@szibis
szibis force-pushed the fix/unwrap-first-last-aggregation branch from b8d8594 to 09e9dcf Compare October 12, 2026 11:01
@github-actions github-actions Bot added size/XL Extra large change and removed size/XL Extra large change labels Oct 12, 2026
szibis added a commit that referenced this pull request Oct 19, 2026
…-aggregation, with its visual fix proof page
@szibis
szibis force-pushed the fix/unwrap-first-last-aggregation branch from 09e9dcf to d6b937e Compare October 19, 2026 10:19
@github-actions github-actions Bot added size/XL Extra large change and removed size/XL Extra large change labels Oct 19, 2026
@szibis
szibis marked this pull request as ready for review October 19, 2026 10:20
szibis added a commit that referenced this pull request Oct 22, 2026
…-aggregation, with its visual fix proof page
@szibis
szibis force-pushed the fix/unwrap-first-last-aggregation branch from d6b937e to 8b338f0 Compare October 22, 2026 14:26
@github-actions github-actions Bot added size/XL Extra large change and removed size/XL Extra large change labels Oct 22, 2026
…ion read each series' sample from VictoriaLogs row_min and row_max instead of a stats function it lacks
…y, the topk, sort and no-by branches are pinned, and the open shapes are registered
…-aggregation, with its visual fix proof page
@szibis
szibis force-pushed the fix/unwrap-first-last-aggregation branch from 8b338f0 to e070299 Compare October 22, 2026 19:42
@github-actions github-actions Bot added size/XL Extra large change and removed size/XL Extra large change labels Oct 22, 2026
@szibis
szibis merged commit 6369fd8 into main Oct 22, 2026
74 of 75 checks passed
@szibis
szibis deleted the fix/unwrap-first-last-aggregation branch October 22, 2026 20:05
szibis added a commit that referenced this pull request Oct 22, 2026
Chart version and README badge for v2.30.0, and the CHANGELOG sections
matched to the published releases: the first_over_time/last_over_time
entry (#728) moves from [2.29.0] to [2.30.0]. #728 merged before the
v2.29.0 metadata pull request, whose added heading then filed the entry
under [2.29.0] although v2.29.0 was cut before #728.
szibis added a commit that referenced this pull request Oct 22, 2026
Chart version and README badge for v2.30.0, and the CHANGELOG sections
matched to the published releases: the first_over_time/last_over_time
entry (#728) moves from [2.29.0] to [2.30.0]. #728 merged before the
v2.29.0 metadata pull request, whose added heading then filed the entry
under [2.29.0] although v2.29.0 was cut before #728.

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

Labels

bugfix Bug fix scope/docs Documentation scope/proxy Proxy core scope/tests Tests scope/translator LogQL translator size/XL Extra large change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant