github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/flameql/flameql.go (about) 1 package flameql 2 3 import "regexp" 4 5 type Query struct { 6 AppName string 7 Matchers []*TagMatcher 8 9 q string // The original query string. 10 } 11 12 func (q *Query) String() string { return q.q } 13 14 type TagMatcher struct { 15 Key string 16 Value string 17 Op 18 19 R *regexp.Regexp 20 } 21 22 type Op int 23 24 const ( 25 // The order should respect operator priority and cost. 26 // Negating operators go first. See IsNegation. 27 _ Op = iota 28 OpNotEqual // != 29 OpNotEqualRegex // !~ 30 OpEqual // = 31 OpEqualRegex // =~ 32 ) 33 34 const ( 35 ReservedTagKeyName = "__name__" 36 ) 37 38 var reservedTagKeys = []string{ 39 ReservedTagKeyName, 40 } 41 42 // IsNegation reports whether the operator assumes negation. 43 func (o Op) IsNegation() bool { return o < OpEqual } 44 45 // ByPriority is a supplemental type for sorting tag matchers. 46 type ByPriority []*TagMatcher 47 48 func (p ByPriority) Len() int { return len(p) } 49 func (p ByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 50 func (p ByPriority) Less(i, j int) bool { return p[i].Op < p[j].Op } 51 52 func (m *TagMatcher) Match(v string) bool { 53 switch m.Op { 54 case OpEqual: 55 return m.Value == v 56 case OpNotEqual: 57 return m.Value != v 58 case OpEqualRegex: 59 return m.R.Match([]byte(v)) 60 case OpNotEqualRegex: 61 return !m.R.Match([]byte(v)) 62 default: 63 panic("invalid match operator") 64 } 65 } 66 67 // ValidateTagKey report an error if the given key k violates constraints. 68 // 69 // The function should be used to validate user input. The function returns 70 // ErrTagKeyReserved if the key is valid but reserved for internal use. 71 func ValidateTagKey(k string) error { 72 if len(k) == 0 { 73 return ErrTagKeyIsRequired 74 } 75 for _, r := range k { 76 if !IsTagKeyRuneAllowed(r) { 77 return newInvalidTagKeyRuneError(k, r) 78 } 79 } 80 if IsTagKeyReserved(k) { 81 return newErr(ErrTagKeyReserved, k) 82 } 83 return nil 84 } 85 86 // ValidateAppName report an error if the given app name n violates constraints. 87 func ValidateAppName(n string) error { 88 if len(n) == 0 { 89 return ErrAppNameIsRequired 90 } 91 for _, r := range n { 92 if !IsAppNameRuneAllowed(r) { 93 return newInvalidAppNameRuneError(n, r) 94 } 95 } 96 return nil 97 } 98 99 func IsTagKeyRuneAllowed(r rune) bool { 100 return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' 101 } 102 103 func IsAppNameRuneAllowed(r rune) bool { 104 return r == '-' || r == '.' || IsTagKeyRuneAllowed(r) 105 } 106 107 func IsTagKeyReserved(k string) bool { 108 for _, s := range reservedTagKeys { 109 if s == k { 110 return true 111 } 112 } 113 return false 114 }