From 57830969c9b90020b466d4259c4423233ffbe733 Mon Sep 17 00:00:00 2001 From: Ted Possible Date: Mon, 10 Feb 2025 14:21:55 -0800 Subject: [PATCH] Adds support for quoted UTF8 label and metric names --- lexer.go | 24 ++++++++++++++++++++++++ parser.go | 27 ++++++++++++++++++++++----- prettifier_test.go | 9 +++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lexer.go b/lexer.go index 9959e15..c6e22c1 100644 --- a/lexer.go +++ b/lexer.go @@ -399,6 +399,30 @@ func unescapeIdent(s string) string { } } +func hasEscapedChars(s string) bool { + i := 0 + for i < len(s) { + r, size := utf8.DecodeRuneInString(s[i:]) + if i == 0 && !isFirstIdentChar(r) || i > 0 && !isIdentChar(r) { + return true + } + i += size + } + return false +} +func fEscapedCharsAppendQuotedIdent(dst []byte, s string) []byte { + if hasEscapedChars(s) { + dst = utf8.AppendRune(dst, '"') + for i := 0; i < len(s); { + r, size := utf8.DecodeRuneInString(s[i:]) + dst = utf8.AppendRune(dst, r) + i += size + } + dst = utf8.AppendRune(dst, '"') + return dst + } + return appendEscapedIdent(dst, s) +} func appendEscapedIdent(dst []byte, s string) []byte { i := 0 for i < len(s) { diff --git a/parser.go b/parser.go index bbc8d6f..44a1b77 100644 --- a/parser.go +++ b/parser.go @@ -1462,7 +1462,7 @@ type labelFilterExpr struct { } func (lfe *labelFilterExpr) AppendString(dst []byte) []byte { - dst = appendEscapedIdent(dst, lfe.Label) + dst = ifEscapedCharsAppendQuotedIdent(dst, lfe.Label) if lfe.Value == nil { return dst } @@ -2267,15 +2267,28 @@ type MetricExpr struct { func appendLabelFilterss(dst []byte, lfss [][]*labelFilterExpr) []byte { offset := 0 metricName := getMetricNameFromLabelFilterss(lfss) + metricNameHasEscapedChars := hasEscapedChars(metricName) + if metricName != "" { offset = 1 - dst = appendEscapedIdent(dst, metricName) + if !metricNameHasEscapedChars { + dst = appendEscapedIdent(dst, metricName) + } else { + dst = append(dst, '{') + dst = ifEscapedCharsAppendQuotedIdent(dst, metricName) + } } if isOnlyMetricNameInLabelFilterss(lfss) { + if metricNameHasEscapedChars { + dst = append(dst, '}') + } return dst } - - dst = append(dst, '{') + if !metricNameHasEscapedChars { + dst = append(dst, '{') + } else { + dst = append(dst, ',', ' ') + } for i, lfs := range lfss { lfs = lfs[offset:] if len(lfs) == 0 { @@ -2335,7 +2348,11 @@ func mustGetMetricName(lfss []*labelFilterExpr) string { } lfs := lfss[0] if lfs.Label != "__name__" || lfs.Value == nil || len(lfs.Value.tokens) != 1 { - return "" + if lfs.IsPossibleMetricName { + return lfs.Label + } else { + return "" + } } metricName, err := extractStringValue(lfs.Value.tokens[0]) if err != nil { diff --git a/prettifier_test.go b/prettifier_test.go index c3a5245..159606e 100644 --- a/prettifier_test.go +++ b/prettifier_test.go @@ -101,7 +101,16 @@ func TestPrettifySuccess(t *testing.T) { // Verify that short queries remain single-line same(`foo`) + another(`{"foo"}`, "foo") + another(`{"3foo"}`, `{"3foo"}`) + another(`{"foo", bar="baz"}`, `foo{bar="baz"}`) + another(`{"foo", "bar"="baz"}`, `foo{bar="baz"}`) same(`foo{bar="baz"}`) + another(`foo{"3bar"="baz"}`, `foo{"3bar"="baz"}`) + another(`foo{"bar3"="baz"}`, `foo{bar3="baz"}`) + same(`"metr\"ic"`) + same(`'metr"ic'`) + same(`{"3foo", bar="baz"}`) same(`foo{bar="baz",x="y" or q="w",r="t"}`) same(`foo{bar="baz"} + rate(x{y="x"}[5m] offset 1h)`)