Repository navigation
fix: reject group(), label_join() and other names Loki does not have, and accept keywords in any case, like Loki - #748
Conversation
⚪ Performance A/B: no change beyond noise264 shape×range — 264 ⚪ same · results vs Loki: 242 same, 0 new difference(s), 22 pre-existing Loki profiles compared (like for like):
Every shape is within noise of the base build (±30% and 100 ms). 29951 characters omitted to fit the comment limit; every row is in the `summary-.json` files of the `perf-ab-smoke` artifactCold (first-run) timings — what a user opening a panel sees
† Loki's results cache answered this cold run (its own counters, or identical answers for windows a minute apart): not a computed time, so it is in no ratio. ↺ Loki cold taken from the first set that ran the same query; Loki's cache answered this one. 48 shape×range above 2× Loki already (listed, or as slow on the base build)
Why these shapes
base 🧭 New baseline candidateThis pull request got the baseline run. Every shape of every set was measured at the smoke's ranges (1h, 4 runs). Nothing was committed. The
The committed column is the newest daily run (7 runs, ranges up to 24h): the direction is comparable, the rows are not the same ones. Above-2× list: 213 rows after this run, 48 added, 0 not above 2× in this run's profile (the daily run's two-run rule decides for the committed list). A profile that did not run leaves its committed rows as they are. Added:
12 min. |
PR Quality ReportCompared against base branch Coverage and tests
Compatibility
Performance smokeLower CPU cost (
State
|
ccd6969 to
c0d9f6d
Compare
|
Verification for PR #748, signed HEAD
The final-head Visual smoke run passed capture, bounded publication, and comment jobs over 245 baseline captures. Its automatic ✅ Visual smoke comment shows base |
✅ Visual smoke: passed with warningsBase Fix proofCaptures 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
explore-748-reject-group-1h — base | PR | Loki Regression check
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 that query to answer like Loki at a shorter range; otherwise label the pull request dd-fields-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-service-logs-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-field-pipeline-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-field-pipeline-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-field-service_version-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-field-service_version-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-fields-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-labels-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-labels-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-labels-namespace-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-labels-namespace-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-patterns-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-patterns-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
dd-service-logs-15m: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
lvl-dd-field-pipeline-pill-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
lvl-dd-label-pod-pill-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
lvl-dd-logs-pill-logfmt-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
lvl-dd-logs-pill-multi-json-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
lvl-dd-logs-pill-otel-1h: history-dependent difference, not gated (1): resource /api/datasources/uid/*/resources/patterns?end=2026-10-29T16%3A19%3
Core set montages (7): base | PR | Lokidd-landing-1h explore-logs-plain-1h explore-metric-plain-1h explore-sum-by-over-binary-1h explore-topk-by-per-step-1h explore-unwrap-sum-1h lvl-explore-rate-errors-by-service-1h Published inline montages: 🧭 New baseline candidateThis pull request got the baseline run: every page of |
14ee8bd to
8bc0fbc
Compare
8bc0fbc to
b56a093
Compare
… accept keywords in any case Loki 3.7.7 has no group aggregation and no label_join: its lexer makes a function token only of the names in functionTokens, so any other name is an IDENTIFIER the grammar cannot place and the query is a 400 parse error at the column of the name. The proxy kept every unknown name(...) as an opaque call and answered it. The parser now keeps opaque only label_replace, vector and approx_topk and reports every other name the way Loki does, also inside a label_replace argument. Loki lower-cases a word before it looks it up, so TOPK(3, X), SUM BY (a) (X), RATE(...) and OFFSET are the keywords they spell, while a label called Rate or Count stays a label. The scanner reads keywords in any case and the query parameter is written with lower-case keywords before a handler reads it.
…e rewriting Loki has neither, and the validator now rejects both before the translator runs, so the marker suffixes, their parsers and the proxy-side rewrites of a matrix response were unreachable.
… and document the change The e2e suite runs the queries Loki rejects against Loki and every Loki-compatible proxy on both query endpoints and compares status and text, and runs uppercase keyword queries and compares the series. group() and label_join() move from the parity and known-gap lists to the error parity list.
…pare the proxy with itself in the e2e The multi-tenant fan-out re-reads the query from the URL, so the lower-case rewrite covers the URL query as well as the parsed form. The proxy tests now send each uppercase query as a GET, a form-encoded POST and a multi-tenant GET. The e2e compares the upper-case answer of the proxy with its own lower-case answer; Loki only has to answer 200 for both spellings.
b56a093 to
fa7924b
Compare


































Result
Loki rejects
group(),label_join(), and other unknown LogQL function names with a 400 parse error. The proxy previously accepted some of them. Conversely, Loki accepts keywords in any case, while the proxy rejected or misrouted uppercase forms such asSUM BY,RATE, and| JSON. This PR returns Loki's error text and source column for unknown names, normalizes recognized keywords across GET, form POST, and multi-tenant requests, and removes the now-unreachablegroup()andlabel_join()translation and response rewriting. Selector labels such asRateremain labels.The branch is rebased onto
mainatbb8f348beeecc1a2e076210c2dc3e98e774d5e36(including #737's visual publisher). The conformance registry markssemantics/proxy-accepts-operators-not-in-lokifixed. This PR also repairs quality-report failure evidence. Visual CI now runs nine general regression scenes on every PR, including docs and CI changes, and adds exact fix scenes for behavior changes. The baseline capture gate stays intact; one existing Compose stack serves main, PR, and Loki.Verification
TestCompat_OperatorsNotInLokiRejectedandTestCompat_UppercaseKeywordsMatchLoki. Direct API proof covered 20 GET/form POST cases across/queryand/query_range: 8 exact Loki 400 errors and 12 matching successful uppercase responses. The TOPK comparison follows the project's ranked-points contract because 20 repeated identical Loki requests produced six tied label sets but one ranked-value result; other cases compare full series and values.bb8f348bmain and the final product Go tree: 17/17 scenes passed in 3.6 minutes. All nine core scenes returned the same data on main and PR; all eight fix: reject group(), label_join() and other names Loki does not have, and accept keywords in any case, like Loki #748 scenes showed a difference on main and PR answers identical to Loki. The local visual gate passed. The final signed head isfa7924bffcbbca3c9998a51a7583e852093df731; current-head visual CI also passed all capture, publisher, and comment jobs over 245 baseline captures.go test -count=1 ./internal/logql ./internal/translator ./internal/proxy, 163 visual tests, 311 CI configuration tests, conformance wiring and parity checks,actionlint, changelog gate, E2E package compile, andgit diff --check. Current-head CI has 72 successful checks, zero failures, one neutral, and four expected skips. Quality reports 19,044 PR tests and 89.2% coverage versus 18,874 and 89.2% on main; performance A/B has 264/264 comparable shape/range pairs within noise and zero new Loki answer differences.Visual proof coverage
explore-748-reject-group-1hgroup(count_over_time({app="api-gateway"}[$__auto]))explore-748-reject-label-join-1hlabel_join(rate({app="api-gateway"}[$__auto]), "d", "-", "app", "level")explore-748-uppercase-sum-1hSUM BY (app) (COUNT_OVER_TIME({env="production"}[$__auto]))explore-748-uppercase-topk-rate-1hTOPK(3, SUM BY (app) (RATE({env="production"}[$__auto])))explore-748-uppercase-json-unwrap-1hSUM BY (app) (SUM_OVER_TIME({env="production"} | JSON | UNWRAP duration_ms [$__auto]))explore-748-uppercase-on-1hSUM BY (app) (COUNT_OVER_TIME({env="production"}[$__auto])) / ON (app) SUM BY (app) (COUNT_OVER_TIME({env="production"}[$__auto]))explore-748-uppercase-bool-1hSUM BY (app) (COUNT_OVER_TIME({env="production"}[$__auto])) > BOOL 0explore-748-uppercase-offset-1hSUM BY (app) (COUNT_OVER_TIME({env="production"}[$__auto] OFFSET 1m))Current-head CI screenshots (main | PR | Loki)
Captured automatically in visual run 40910139389, base
bb8f348b, headfa7924bf.Reject group(): main accepted, PR and Loki reject
Reject label_join(): main accepted, PR and Loki reject
Uppercase SUM BY / COUNT_OVER_TIME: main 400, PR and Loki graph
Uppercase TOPK / SUM / RATE: main 400, PR and Loki ranked graph
Uppercase JSON / UNWRAP: main 400, PR and Loki unwrap graph
Uppercase ON: main 400, PR and Loki joined graph
Uppercase BOOL: main 400, PR and Loki Boolean graph
Uppercase OFFSET: main 400, PR and Loki shifted graph
The automatic ✅ Visual smoke comment displays all eight exact fix montages and nine general core montages inline and open. It records base
bb8f348band headfa7924bf; all 17 raw image URLs returned HTTP 200image/png. Transport, tenant, and quality-report collector behavior are API/CI properties proven by tests and report artifacts.