github.com/netdata/go.d.plugin@v0.58.1/pkg/prometheus/selector/parse.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package selector
     4  
     5  import (
     6  	"fmt"
     7  	"regexp"
     8  	"strings"
     9  
    10  	"github.com/netdata/go.d.plugin/pkg/matcher"
    11  )
    12  
    13  var (
    14  	reLV = regexp.MustCompile(`^(?P<label_name>[a-zA-Z0-9_]+)(?P<op>=~|!~|=\*|!\*|=|!=)"(?P<pattern>.+)"$`)
    15  )
    16  
    17  func Parse(expr string) (Selector, error) {
    18  	var srs []Selector
    19  	lvs := strings.Split(unsugarExpr(expr), ",")
    20  
    21  	for _, lv := range lvs {
    22  		sr, err := parseSelector(lv)
    23  		if err != nil {
    24  			return nil, err
    25  		}
    26  		srs = append(srs, sr)
    27  	}
    28  
    29  	switch len(srs) {
    30  	case 0:
    31  		return nil, nil
    32  	case 1:
    33  		return srs[0], nil
    34  	default:
    35  		return And(srs[0], srs[1], srs[2:]...), nil
    36  	}
    37  }
    38  
    39  func parseSelector(line string) (Selector, error) {
    40  	sub := reLV.FindStringSubmatch(strings.TrimSpace(line))
    41  	if sub == nil {
    42  		return nil, fmt.Errorf("invalid selector syntax: '%s'", line)
    43  	}
    44  
    45  	name, op, pattern := sub[1], sub[2], strings.Trim(sub[3], "\"")
    46  
    47  	var m matcher.Matcher
    48  	var err error
    49  
    50  	switch op {
    51  	case OpEqual, OpNegEqual:
    52  		m, err = matcher.NewStringMatcher(pattern, true, true)
    53  	case OpRegexp, OpNegRegexp:
    54  		m, err = matcher.NewRegExpMatcher(pattern)
    55  	case OpSimplePatterns, OpNegSimplePatterns:
    56  		m, err = matcher.NewSimplePatternsMatcher(pattern)
    57  	default:
    58  		err = fmt.Errorf("unknown matching operator: %s", op)
    59  	}
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	sr := labelSelector{
    65  		name: name,
    66  		m:    m,
    67  	}
    68  
    69  	if neg := strings.HasPrefix(op, "!"); neg {
    70  		return Not(sr), nil
    71  	}
    72  	return sr, nil
    73  }
    74  
    75  func unsugarExpr(expr string) string {
    76  	// name                => __name__=*"name"
    77  	// name{label="value"} => __name__=*"name",label="value"
    78  	// {label="value"}     => label="value"
    79  	expr = strings.TrimSpace(expr)
    80  
    81  	switch idx := strings.IndexByte(expr, '{'); true {
    82  	case idx == -1:
    83  		expr = fmt.Sprintf(`__name__%s"%s"`,
    84  			OpSimplePatterns,
    85  			strings.TrimSpace(expr),
    86  		)
    87  	case idx == 0:
    88  		expr = strings.Trim(expr, "{}")
    89  	default:
    90  		expr = fmt.Sprintf(`__name__%s"%s",%s`,
    91  			OpSimplePatterns,
    92  			strings.TrimSpace(expr[:idx]),
    93  			strings.Trim(expr[idx:], "{}"),
    94  		)
    95  	}
    96  	return expr
    97  }