Fix escaping for `Matcher.String()`
Now the string created will correctly parse back. Signed-off-by: beorn7 <beorn@grafana.com>
This commit is contained in:
parent
f7742393ae
commit
e1ab2477c0
|
@ -16,6 +16,7 @@ package labels
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MatchType is an enum for label matching types.
|
// MatchType is an enum for label matching types.
|
||||||
|
@ -69,7 +70,7 @@ func NewMatcher(t MatchType, n, v string) (*Matcher, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Matcher) String() string {
|
func (m *Matcher) String() string {
|
||||||
return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value)
|
return fmt.Sprintf(`%s%s"%s"`, m.Name, m.Type, openMetricsEscape(m.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches returns whether the matcher matches the given string value.
|
// Matches returns whether the matcher matches the given string value.
|
||||||
|
@ -86,3 +87,16 @@ func (m *Matcher) Matches(s string) bool {
|
||||||
}
|
}
|
||||||
panic("labels.Matcher.Matches: invalid match type")
|
panic("labels.Matcher.Matches: invalid match type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// openMetricsEscape is similar to the usual string escaping, but more
|
||||||
|
// restricted. It merely replaces a new-line character with '\n', a double-quote
|
||||||
|
// character with '\"', and a backslack with '\\', which is the escaping used by
|
||||||
|
// OpenMetrics.
|
||||||
|
func openMetricsEscape(s string) string {
|
||||||
|
r := strings.NewReplacer(
|
||||||
|
`\`, `\\`,
|
||||||
|
"\n", `\n`,
|
||||||
|
`"`, `\"`,
|
||||||
|
)
|
||||||
|
return r.Replace(s)
|
||||||
|
}
|
||||||
|
|
|
@ -122,3 +122,72 @@ func TestMatcher(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatcherString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
op MatchType
|
||||||
|
value string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchEqual,
|
||||||
|
value: `bar`,
|
||||||
|
want: `foo="bar"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchNotEqual,
|
||||||
|
value: `bar`,
|
||||||
|
want: `foo!="bar"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchRegexp,
|
||||||
|
value: `bar`,
|
||||||
|
want: `foo=~"bar"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchNotRegexp,
|
||||||
|
value: `bar`,
|
||||||
|
want: `foo!~"bar"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchEqual,
|
||||||
|
value: `back\slash`,
|
||||||
|
want: `foo="back\\slash"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchEqual,
|
||||||
|
value: `double"quote`,
|
||||||
|
want: `foo="double\"quote"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchEqual,
|
||||||
|
value: `new
|
||||||
|
line`,
|
||||||
|
want: `foo="new\nline"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `foo`,
|
||||||
|
op: MatchEqual,
|
||||||
|
value: `tab stop`,
|
||||||
|
want: `foo="tab stop"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
m, err := NewMatcher(test.op, test.name, test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := m.String(); got != test.want {
|
||||||
|
t.Errorf("Unexpected string representation of matcher; want %v, got %v", test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue