fix/promql/parser: Fix utf-8 label quoting in format_query endpoint

Signed-off-by: ADITYA TIWARI <adityatiwari342005@gmail.com>
This commit is contained in:
ADITYA TIWARI 2025-12-14 20:18:06 +00:00
parent 6f18cc3074
commit 5b299ef99e
2 changed files with 62 additions and 3 deletions

View file

@ -109,7 +109,7 @@ func writeLabels(b *bytes.Buffer, ss []string) {
if i > 0 {
b.WriteString(", ")
}
if !model.LegacyValidation.IsValidMetricName(s) {
if !model.LegacyValidation.IsValidLabelName(s) {
b.Write(strconv.AppendQuote(b.AvailableBuffer(), s))
} else {
b.WriteString(s)
@ -145,6 +145,19 @@ func (node *BinaryExpr) ShortString() string {
return node.Op.String() + node.returnBool() + node.getMatchingStr()
}
// joinLabels joins label names, quoting them if they are not valid legacy label names.
func joinLabels(labels []string) string {
quoted := make([]string, 0, len(labels))
for _, label := range labels {
if model.LegacyValidation.IsValidLabelName(label) {
quoted = append(quoted, label)
} else {
quoted = append(quoted, strconv.Quote(label))
}
}
return strings.Join(quoted, ", ")
}
func (node *BinaryExpr) getMatchingStr() string {
matching := ""
vm := node.VectorMatching
@ -154,7 +167,7 @@ func (node *BinaryExpr) getMatchingStr() string {
if vm.On {
vmTag = "on"
}
matching = fmt.Sprintf(" %s (%s)", vmTag, strings.Join(vm.MatchingLabels, ", "))
matching = fmt.Sprintf(" %s (%s)", vmTag, joinLabels(vm.MatchingLabels))
}
if vm.Card == CardManyToOne || vm.Card == CardOneToMany {
@ -162,7 +175,7 @@ func (node *BinaryExpr) getMatchingStr() string {
if vm.Card == CardManyToOne {
vmCard = "left"
}
matching += fmt.Sprintf(" group_%s (%s)", vmCard, strings.Join(vm.Include, ", "))
matching += fmt.Sprintf(" group_%s (%s)", vmCard, joinLabels(vm.Include))
}
}
return matching

View file

@ -269,6 +269,10 @@ func TestExprString(t *testing.T) {
{
in: `predict_linear(foo[1h], 3000)`,
},
{
in: `sum by("üüü") (foo)`,
out: `sum by ("üüü") (foo)`,
},
}
EnableExtendedRangeSelectors = true
@ -394,3 +398,45 @@ func TestVectorSelector_String(t *testing.T) {
})
}
}
func TestBinaryExprUTF8Labels(t *testing.T) {
testCases := []struct {
name string
input string
expected string
}{
{
name: "UTF-8 labels in on clause",
input: `foo / on("äää") bar`,
expected: `foo / on ("äää") bar`,
},
{
name: "UTF-8 labels in group_left clause",
input: `foo / on("äää") group_left("ööö") bar`,
expected: `foo / on ("äää") group_left ("ööö") bar`,
},
{
name: "Mixed legacy and UTF-8 labels",
input: `foo / on(legacy, "üüü") bar`,
expected: `foo / on (legacy, "üüü") bar`,
},
{
name: "Legacy labels only (should not quote)",
input: `foo / on(job, instance) bar`,
expected: `foo / on (job, instance) bar`,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
expr, err := ParseExpr(tc.input)
if err != nil {
t.Fatalf("Failed to parse: %v", err)
}
result := expr.String()
if result != tc.expected {
t.Errorf("Expected: %s\nGot: %s", tc.expected, result)
}
})
}
}