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  }