Fix parser.VectorSelector.String() with empty name matcher (#14015)

The check fell into "this matcher equals vector selector's name" case when vector selector doesn't have a name and the matcher is an explicit matcher for an empty __name__ label.

To provide some context about why this is important: some downstream projects use the promql.Parse(expr.String()) to clone an expression's AST, and with this bug that matcher disappears in the cloning.

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
This commit is contained in:
Oleg Zaytsev 2024-05-06 11:51:08 +02:00 committed by GitHub
parent 93be83069e
commit 4b7a44c7a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 15 additions and 2 deletions

View file

@ -204,8 +204,8 @@ func (node *VectorSelector) String() string {
labelStrings = make([]string, 0, len(node.LabelMatchers)-1) labelStrings = make([]string, 0, len(node.LabelMatchers)-1)
} }
for _, matcher := range node.LabelMatchers { for _, matcher := range node.LabelMatchers {
// Only include the __name__ label if its equality matching and matches the name. // Only include the __name__ label if its equality matching and matches the name, but don't skip if it's an explicit empty name matcher.
if matcher.Name == labels.MetricName && matcher.Type == labels.MatchEqual && matcher.Value == node.Name { if matcher.Name == labels.MetricName && matcher.Type == labels.MatchEqual && matcher.Value == node.Name && matcher.Value != "" {
continue continue
} }
labelStrings = append(labelStrings, matcher.String()) labelStrings = append(labelStrings, matcher.String())

View file

@ -135,6 +135,9 @@ func TestExprString(t *testing.T) {
{ {
in: `a[1m] @ end()`, in: `a[1m] @ end()`,
}, },
{
in: `{__name__="",a="x"}`,
},
} }
for _, test := range inputs { for _, test := range inputs {
@ -216,6 +219,16 @@ func TestVectorSelector_String(t *testing.T) {
}, },
expected: `{__name__="foobar"}`, expected: `{__name__="foobar"}`,
}, },
{
name: "empty name matcher",
vs: VectorSelector{
LabelMatchers: []*labels.Matcher{
labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, ""),
labels.MustNewMatcher(labels.MatchEqual, "a", "x"),
},
},
expected: `{__name__="",a="x"}`,
},
} { } {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, tc.vs.String()) require.Equal(t, tc.expected, tc.vs.String())