Skip to content

fix(prometheus): use lezer tree instead of greedy regex for range duration - #86

Open
algojogacor wants to merge 1 commit into
grafana:mainfrom
algojogacor:main
Open

fix(prometheus): use lezer tree instead of greedy regex for range duration#86
algojogacor wants to merge 1 commit into
grafana:mainfrom
algojogacor:main

Conversation

@algojogacor

Copy link
Copy Markdown

Summary

Fixes #97

The PromQL query builder used the greedy regex /\[(.+)\]/ to extract range duration (e.g., 5m in rate(metric[5m])) from function call text. This broke when label filter values contained [ characters, because the regex matched from the first [ (inside the label value) to the last ] (the duration bracket).

Root Cause

parsing.ts line 254: getString(expr, node).match(/\[(.+)\]/) extracts the full function call text and applies a greedy regex. For a query like rate(metric{label=~"value[0-9]"}[5m]), the regex captures 0-9]"}[5m instead of 5m.

Fix

Replace the regex with lezer syntax tree traversal. The FunctionCallBody already has a parsed MatrixSelector child node. From the MatrixSelector, extract the NumberDurationLiteral child to get the exact duration text.

  • Import MatrixSelector from @prometheus-io/lezer-promql
  • Traverse body.getChild(MatrixSelector)getChild(NumberDurationLiteral)
  • Extract duration using the existing getString(expr, durationNode) pattern

Changes

  • packages/grafana-prometheus/src/querybuilder/parsing.ts: Replace greedy regex with lezer tree traversal (+11 -6 lines)
  • packages/grafana-prometheus/src/querybuilder/parsing.test.ts: Add test for [ in label filter values (+23 -0 lines)

Testing

  • rate() with [ in label value: rate(metric{label=~"value[0-9]"}[5m]) → correctly parses duration as 5m
  • rate() without [ in label (existing test preserved): rate(counters_logins{app="frontend"}[5m]) → still works ✅
  • Nested query with interval variable (existing test preserved): avg(rate(...)[$__rate_interval]) → still works ✅

…e duration

The PromQL query builder used /\[(.+)\]/ to extract range duration
from function calls. This greedy regex matched from the first '[' to
the last ']', breaking when label filter values contained brackets.

Example: rate(metric{label=~"value[0-9]"}[5m]) would capture
'0-9]"}[5m' instead of '5m'.

Replace the regex with lezer syntax tree traversal using MatrixSelector
and NumberDurationLiteral nodes, which correctly identify the range
duration regardless of brackets in label values.

Fixes: grafana/grafana#124522

Signed-off-by: Arya Rizky <arya@algojogacor.dev>
@cla-assistant

cla-assistant Bot commented May 12, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

2 similar comments
@cla-assistant

cla-assistant Bot commented May 12, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@cla-assistant

cla-assistant Bot commented May 12, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@itsmylife

itsmylife commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

@algojogacor Thank you for your contribution. I'm reviewing it but I won't be able to merge it unless you sign your commits. Our CI dictates that all commits must be signed. Also you have to sign CLA: #86 (comment)
One more point, could you please merge latest main branch into your branch and push?

@itsmylife itsmylife assigned itsmylife and unassigned itsmylife Jul 3, 2026

@itsmylife itsmylife left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. Here is my review: The bug is real and your approach of using the lezer tree instead of regex is the right direction.

But there is a critical mistake in the implementation. The PR uses getChild(NumberDurationLiteral) to find the duration inside MatrixSelector, but if you look at the lezer-promql grammar, the correct node type inside a MatrixSelector is NumberDurationLiteralInDurationContext, not NumberDurationLiteral:

MatrixSelector {
  expr "[" NumberDurationLiteralInDurationContext "]"
}

These are two different node IDs (140 vs 141). The getChild() call will silently return null for every valid duration literal, so interval stays '' and params is never populated. This means the fix would actually break parsing of all range functions, not just the ones with [ in label values.

Also, the original code has a comment explaining it intentionally uses the regex shortcut to handle Grafana template variables like $__rate_interval, because the lezer parser produces an error node for those (they are not valid PromQL). The PR does not address this case at all. A pure tree-traversal approach needs a fallback for when the MatrixSelector child is an error node.

Please add a test case for rate(metric{label=~"value[0-9]"}[5m]) and verify it produces params: ['5m'] and not an empty array.

Thanks a lot.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 2 weeks if no further activity occurs. Please feel free to give a status update or ping for review. Thank you for your contributions!

@github-actions github-actions Bot added the stale Issue with no recent activity label Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale Issue with no recent activity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PromQL: builder can not parse promql correctly when filtering condition contains "["

3 participants