github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/syntax/parser.go (about)

     1  package syntax
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  	"sync"
     9  	"text/scanner"
    10  
    11  	"github.com/prometheus/prometheus/model/labels"
    12  	promql_parser "github.com/prometheus/prometheus/promql/parser"
    13  
    14  	"github.com/grafana/loki/pkg/logqlmodel"
    15  	"github.com/grafana/loki/pkg/util"
    16  )
    17  
    18  const (
    19  	EmptyMatchers = "{}"
    20  
    21  	errAtleastOneEqualityMatcherRequired = "queries require at least one regexp or equality matcher that does not have an empty-compatible value. For instance, app=~\".*\" does not meet this requirement, but app=~\".+\" will"
    22  )
    23  
    24  var parserPool = sync.Pool{
    25  	New: func() interface{} {
    26  		p := &parser{
    27  			p:      &exprParserImpl{},
    28  			Reader: strings.NewReader(""),
    29  			lexer:  &lexer{},
    30  		}
    31  		return p
    32  	},
    33  }
    34  
    35  const maxInputSize = 5120
    36  
    37  func init() {
    38  	// Improve the error messages coming out of yacc.
    39  	exprErrorVerbose = true
    40  	// uncomment when you need to understand yacc rule tree.
    41  	// exprDebug = 3
    42  	for str, tok := range tokens {
    43  		exprToknames[tok-exprPrivate+1] = str
    44  	}
    45  }
    46  
    47  type parser struct {
    48  	p *exprParserImpl
    49  	*lexer
    50  	expr Expr
    51  	*strings.Reader
    52  }
    53  
    54  func (p *parser) Parse() (Expr, error) {
    55  	p.lexer.errs = p.lexer.errs[:0]
    56  	p.lexer.Scanner.Error = func(_ *scanner.Scanner, msg string) {
    57  		p.lexer.Error(msg)
    58  	}
    59  	e := p.p.Parse(p)
    60  	if e != 0 || len(p.lexer.errs) > 0 {
    61  		return nil, p.lexer.errs[0]
    62  	}
    63  	return p.expr, nil
    64  }
    65  
    66  // ParseExpr parses a string and returns an Expr.
    67  func ParseExpr(input string) (Expr, error) {
    68  	expr, err := parseExprWithoutValidation(input)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	if err := validateExpr(expr); err != nil {
    73  		return nil, err
    74  	}
    75  	return expr, nil
    76  }
    77  
    78  func parseExprWithoutValidation(input string) (expr Expr, err error) {
    79  	if len(input) >= maxInputSize {
    80  		return nil, logqlmodel.NewParseError(fmt.Sprintf("input size too long (%d > %d)", len(input), maxInputSize), 0, 0)
    81  	}
    82  
    83  	defer func() {
    84  		if r := recover(); r != nil {
    85  			var ok bool
    86  			if err, ok = r.(error); ok {
    87  				if errors.Is(err, logqlmodel.ErrParse) {
    88  					return
    89  				}
    90  				err = logqlmodel.NewParseError(err.Error(), 0, 0)
    91  			}
    92  		}
    93  	}()
    94  
    95  	p := parserPool.Get().(*parser)
    96  	defer parserPool.Put(p)
    97  
    98  	p.Reader.Reset(input)
    99  	p.lexer.Init(p.Reader)
   100  	return p.Parse()
   101  }
   102  
   103  func validateExpr(expr Expr) error {
   104  	switch e := expr.(type) {
   105  	case SampleExpr:
   106  		err := validateSampleExpr(e)
   107  		if err != nil {
   108  			return err
   109  		}
   110  	case LogSelectorExpr:
   111  		err := validateMatchers(e.Matchers())
   112  		if err != nil {
   113  			return err
   114  		}
   115  	default:
   116  		return logqlmodel.NewParseError(fmt.Sprintf("unexpected expression type: %v", e), 0, 0)
   117  	}
   118  	return nil
   119  }
   120  
   121  // validateMatchers checks whether a query would touch all the streams in the query range or uses at least one matcher to select specific streams.
   122  func validateMatchers(matchers []*labels.Matcher) error {
   123  	if len(matchers) == 0 {
   124  		return nil
   125  	}
   126  	_, matchers = util.SplitFiltersAndMatchers(matchers)
   127  	if len(matchers) == 0 {
   128  		return logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0)
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  // ParseMatchers parses a string and returns labels matchers, if the expression contains
   135  // anything else it will return an error.
   136  func ParseMatchers(input string) ([]*labels.Matcher, error) {
   137  	expr, err := ParseExpr(input)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	matcherExpr, ok := expr.(*MatchersExpr)
   142  	if !ok {
   143  		return nil, errors.New("only label matchers is supported")
   144  	}
   145  	return matcherExpr.Mts, nil
   146  }
   147  
   148  func MatchersString(xs []*labels.Matcher) string {
   149  	return newMatcherExpr(xs).String()
   150  }
   151  
   152  // ParseSampleExpr parses a string and returns the sampleExpr
   153  func ParseSampleExpr(input string) (SampleExpr, error) {
   154  	expr, err := ParseExpr(input)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	sampleExpr, ok := expr.(SampleExpr)
   159  	if !ok {
   160  		return nil, errors.New("only sample expression supported")
   161  	}
   162  
   163  	return sampleExpr, nil
   164  }
   165  
   166  func validateSampleExpr(expr SampleExpr) error {
   167  	switch e := expr.(type) {
   168  	case *BinOpExpr:
   169  		if err := validateSampleExpr(e.SampleExpr); err != nil {
   170  			return err
   171  		}
   172  
   173  		return validateSampleExpr(e.RHS)
   174  	case *LiteralExpr:
   175  		return nil
   176  	default:
   177  		return validateMatchers(expr.Selector().Matchers())
   178  	}
   179  }
   180  
   181  // ParseLogSelector parses a log selector expression `{app="foo"} |= "filter"`
   182  func ParseLogSelector(input string, validate bool) (LogSelectorExpr, error) {
   183  	expr, err := parseExprWithoutValidation(input)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	logSelector, ok := expr.(LogSelectorExpr)
   188  	if !ok {
   189  		return nil, errors.New("only log selector is supported")
   190  	}
   191  	if validate {
   192  		if err := validateExpr(expr); err != nil {
   193  			return nil, err
   194  		}
   195  	}
   196  	return logSelector, nil
   197  }
   198  
   199  // ParseLabels parses labels from a string using logql parser.
   200  func ParseLabels(lbs string) (labels.Labels, error) {
   201  	ls, err := promql_parser.ParseMetric(lbs)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	sort.Sort(ls)
   206  	return ls, nil
   207  }