github.com/amazechain/amc@v0.1.3/internal/metrics/prometheus/parseing.go (about) 1 package prometheus 2 3 import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "github.com/prometheus/client_golang/prometheus" 9 ) 10 11 func parseMetric(s string) (string, prometheus.Labels, error) { 12 if len(s) == 0 { 13 return "", nil, fmt.Errorf("metric cannot be empty") 14 } 15 n := strings.IndexByte(s, '{') 16 if n < 0 { 17 if err := validateIdent(s); err != nil { 18 return "", nil, err 19 } 20 21 return s, nil, nil 22 } 23 ident := s[:n] 24 s = s[n+1:] 25 if err := validateIdent(ident); err != nil { 26 return "", nil, err 27 } 28 if len(s) == 0 || s[len(s)-1] != '}' { 29 return "", nil, fmt.Errorf("missing closing curly brace at the end of %q", ident) 30 } 31 32 tags, err := parseTags(s[:len(s)-1]) 33 34 if err != nil { 35 return "", nil, err 36 } 37 38 return ident, tags, nil 39 } 40 41 func parseTags(s string) (prometheus.Labels, error) { 42 if len(s) == 0 { 43 return nil, nil 44 } 45 46 var labels prometheus.Labels 47 48 for { 49 n := strings.IndexByte(s, '=') 50 if n < 0 { 51 return nil, fmt.Errorf("missing `=` after %q", s) 52 } 53 ident := s[:n] 54 s = s[n+1:] 55 if err := validateIdent(ident); err != nil { 56 return nil, err 57 } 58 if len(s) == 0 || s[0] != '"' { 59 return nil, fmt.Errorf("missing starting `\"` for %q value; tail=%q", ident, s) 60 } 61 s = s[1:] 62 63 value := "" 64 65 for { 66 n = strings.IndexByte(s, '"') 67 if n < 0 { 68 return nil, fmt.Errorf("missing trailing `\"` for %q value; tail=%q", ident, s) 69 } 70 m := n 71 for m > 0 && s[m-1] == '\\' { 72 m-- 73 } 74 if (n-m)%2 == 1 { 75 value = value + s[:n] 76 s = s[n+1:] 77 continue 78 } 79 value = value + s[:n] 80 if labels == nil { 81 labels = prometheus.Labels{} 82 } 83 labels[ident] = value 84 s = s[n+1:] 85 if len(s) == 0 { 86 return labels, nil 87 } 88 if !strings.HasPrefix(s, ",") { 89 return nil, fmt.Errorf("missing `,` after %q value; tail=%q", ident, s) 90 } 91 s = skipSpace(s[1:]) 92 break 93 } 94 } 95 } 96 97 func skipSpace(s string) string { 98 for len(s) > 0 && s[0] == ' ' { 99 s = s[1:] 100 } 101 return s 102 } 103 104 func validateIdent(s string) error { 105 if !identRegexp.MatchString(s) { 106 return fmt.Errorf("invalid identifier %q", s) 107 } 108 return nil 109 } 110 111 var identRegexp = regexp.MustCompile("^[a-zA-Z_:.][a-zA-Z0-9_:.]*$")