metrics/validator.go

82 lines
1.6 KiB
Go
Raw Normal View History

2019-04-08 16:29:16 +03:00
package metrics
import (
"fmt"
"regexp"
"strings"
)
func validateMetric(s string) error {
if len(s) == 0 {
return fmt.Errorf("metric cannot be empty")
}
if s[0] == 0 {
// Skip special case metrics. See Histogram for details.
return nil
}
n := strings.IndexByte(s, '{')
if n < 0 {
return validateIdent(s)
}
ident := s[:n]
s = s[n+1:]
if err := validateIdent(ident); err != nil {
return err
}
if len(s) == 0 || s[len(s)-1] != '}' {
return fmt.Errorf("missing closing curly brace at the end of %q", ident)
}
return validateTags(s[:len(s)-1])
}
func validateTags(s string) error {
if len(s) == 0 {
return nil
}
for {
n := strings.IndexByte(s, '=')
if n < 0 {
return fmt.Errorf("missing `=` after %q", s)
}
ident := s[:n]
s = s[n+1:]
if err := validateIdent(ident); err != nil {
return err
}
if len(s) == 0 || s[0] != '"' {
return fmt.Errorf("missing starting `\"` for %q value; tail=%q", ident, s)
}
s = s[1:]
again:
n = strings.IndexByte(s, '"')
if n < 0 {
return fmt.Errorf("missing trailing `\"` for %q value; tail=%q", ident, s)
}
m := n
for m > 0 && s[m-1] == '\\' {
m--
}
if (n-m)%2 == 1 {
s = s[n+1:]
goto again
}
s = s[n+1:]
if len(s) == 0 {
return nil
}
if !strings.HasPrefix(s, ", ") {
return fmt.Errorf("missing `, ` after %q value; tail=%q", ident, s)
}
s = s[2:]
}
}
func validateIdent(s string) error {
if !identRegexp.MatchString(s) {
return fmt.Errorf("invalid identifier %q", s)
}
return nil
}
var identRegexp = regexp.MustCompile("^[a-zA-Z_:][a-zA-Z0-9_:]*$")