Skip to content

Commit

Permalink
[query] Standardize parse function logic (#2499)
Browse files Browse the repository at this point in the history
  • Loading branch information
arnikola authored Jul 30, 2020
1 parent 6a805d3 commit 6435114
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 11 deletions.
5 changes: 3 additions & 2 deletions src/query/api/v1/handler/prometheus/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import (
xhttp "github.com/m3db/m3/src/x/net/http"

"github.com/golang/snappy"
promql "github.com/prometheus/prometheus/promql/parser"
)

const (
Expand Down Expand Up @@ -223,6 +222,7 @@ func parseTagCompletionQueries(r *http.Request) ([]string, error) {
// ParseSeriesMatchQuery parses all params from the GET request.
func ParseSeriesMatchQuery(
r *http.Request,
parseOpts xpromql.ParseOptions,
tagOptions models.TagOptions,
) ([]*storage.FetchQuery, *xhttp.ParseError) {
r.ParseForm()
Expand All @@ -244,8 +244,9 @@ func ParseSeriesMatchQuery(
}

queries := make([]*storage.FetchQuery, len(matcherValues))
fn := parseOpts.MetricSelectorFn()
for i, s := range matcherValues {
promMatchers, err := promql.ParseMetricSelector(s)
promMatchers, err := fn(s)
if err != nil {
return nil, xhttp.NewParseError(err, http.StatusBadRequest)
}
Expand Down
5 changes: 4 additions & 1 deletion src/query/api/v1/handler/prometheus/remote/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/m3db/m3/src/query/api/v1/options"
"github.com/m3db/m3/src/query/block"
"github.com/m3db/m3/src/query/models"
"github.com/m3db/m3/src/query/parser/promql"
"github.com/m3db/m3/src/query/storage"
"github.com/m3db/m3/src/query/util/logging"
"github.com/m3db/m3/src/x/instrument"
Expand All @@ -55,6 +56,7 @@ type PromSeriesMatchHandler struct {
tagOptions models.TagOptions
fetchOptionsBuilder handleroptions.FetchOptionsBuilder
instrumentOpts instrument.Options
parseOpts promql.ParseOptions
}

// NewPromSeriesMatchHandler returns a new instance of handler.
Expand All @@ -64,6 +66,7 @@ func NewPromSeriesMatchHandler(opts options.HandlerOptions) http.Handler {
storage: opts.Storage(),
fetchOptionsBuilder: opts.FetchOptionsBuilder(),
instrumentOpts: opts.InstrumentOpts(),
parseOpts: opts.Engine().Options().ParseOptions(),
}
}

Expand All @@ -73,7 +76,7 @@ func (h *PromSeriesMatchHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
w.Header().Set(xhttp.HeaderContentType, xhttp.ContentTypeJSON)
w.Header().Set("Access-Control-Allow-Origin", "*")

queries, err := prometheus.ParseSeriesMatchQuery(r, h.tagOptions)
queries, err := prometheus.ParseSeriesMatchQuery(r, h.parseOpts, h.tagOptions)
if err != nil {
logger.Error("unable to parse series match values to query", zap.Error(err))
xhttp.Error(w, err, http.StatusBadRequest)
Expand Down
11 changes: 8 additions & 3 deletions src/query/api/v1/handler/prometheus/remote/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/m3db/m3/src/query/executor"
"github.com/m3db/m3/src/query/generated/proto/prompb"
"github.com/m3db/m3/src/query/models"
xpromql "github.com/m3db/m3/src/query/parser/promql"
"github.com/m3db/m3/src/query/storage"
"github.com/m3db/m3/src/query/ts"
"github.com/m3db/m3/src/query/util"
Expand Down Expand Up @@ -264,7 +265,10 @@ type ReadResult struct {

// ParseExpr parses a prometheus request expression into the constituent
// fetches, rather than the full query application.
func ParseExpr(r *http.Request) (*prompb.ReadRequest, *xhttp.ParseError) {
func ParseExpr(
r *http.Request,
opts xpromql.ParseOptions,
) (*prompb.ReadRequest, *xhttp.ParseError) {
var req *prompb.ReadRequest
exprParam := strings.TrimSpace(r.FormValue("query"))
if len(exprParam) == 0 {
Expand All @@ -283,8 +287,9 @@ func ParseExpr(r *http.Request) (*prompb.ReadRequest, *xhttp.ParseError) {
return nil, xhttp.NewParseError(err, http.StatusBadRequest)
}

fn := opts.ParseFn()
req = &prompb.ReadRequest{}
expr, err := promql.ParseExpr(exprParam)
expr, err := fn(exprParam)
if err != nil {
return nil, xhttp.NewParseError(err, http.StatusBadRequest)
}
Expand Down Expand Up @@ -367,7 +372,7 @@ func ParseRequest(
var rErr *xhttp.ParseError
switch {
case r.Method == http.MethodGet && strings.TrimSpace(r.FormValue("query")) != "":
req, rErr = ParseExpr(r)
req, rErr = ParseExpr(r, opts.Engine().Options().ParseOptions())
default:
req, rErr = parseCompressedRequest(r)
}
Expand Down
3 changes: 2 additions & 1 deletion src/query/api/v1/handler/prometheus/remote/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"github.com/m3db/m3/src/query/executor"
"github.com/m3db/m3/src/query/generated/proto/prompb"
"github.com/m3db/m3/src/query/models"
xpromql "github.com/m3db/m3/src/query/parser/promql"
"github.com/m3db/m3/src/query/storage"
"github.com/m3db/m3/src/query/test"
"github.com/m3db/m3/src/query/test/m3"
Expand Down Expand Up @@ -91,7 +92,7 @@ func TestParseExpr(t *testing.T) {
start := time.Now().Truncate(time.Hour)
req := httptest.NewRequest(http.MethodPost, "/", buildBody(query, start))
req.Header.Add(xhttp.HeaderContentType, xhttp.ContentTypeFormURLEncoded)
readReq, err := ParseExpr(req)
readReq, err := ParseExpr(req, xpromql.NewParseOptions())
require.NoError(t, err)

q := func(start, end time.Time, matchers []*prompb.LabelMatcher) *prompb.Query {
Expand Down
33 changes: 29 additions & 4 deletions src/query/parser/promql/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package promql
import (
"github.com/m3db/m3/src/query/models"
"github.com/m3db/m3/src/query/parser"
"github.com/prometheus/prometheus/pkg/labels"
pql "github.com/prometheus/prometheus/promql/parser"
)

Expand All @@ -45,39 +46,63 @@ func defaultParseFn(query string) (pql.Expr, error) {
return pql.ParseExpr(query)
}

// MetricSelectorFn is a function that parses a query to Prometheus selectors.
type MetricSelectorFn func(query string) ([]*labels.Matcher, error)

func defaultMetricSelectorFn(query string) ([]*labels.Matcher, error) {
return pql.ParseMetricSelector(query)
}

// ParseOptions are options for the Prometheus parser.
type ParseOptions interface {
// ParseFn gets the parse function.
ParseFn() ParseFn
// SetParseFn sets the parse function.
SetParseFn(f ParseFn) ParseOptions

// MetricSelectorFn gets the metric selector function.
MetricSelectorFn() MetricSelectorFn
// SetMetricSelectorFn sets the metric selector function.
SetMetricSelectorFn(f MetricSelectorFn) ParseOptions

// FunctionParseExpr gets the parsing function.
FunctionParseExpr() ParseFunctionExpr
// SetFunctionParseExpr sets the parsing function.
SetFunctionParseExpr(f ParseFunctionExpr) ParseOptions
}

type parseOptions struct {
fn ParseFn
parseFn ParseFn
selectorFn MetricSelectorFn
fnParseExpr ParseFunctionExpr
}

// NewParseOptions creates a new parse options.
func NewParseOptions() ParseOptions {
return &parseOptions{
fn: defaultParseFn,
parseFn: defaultParseFn,
selectorFn: defaultMetricSelectorFn,
fnParseExpr: NewFunctionExpr,
}
}

func (o *parseOptions) ParseFn() ParseFn {
return o.fn
return o.parseFn
}

func (o *parseOptions) SetParseFn(f ParseFn) ParseOptions {
opts := *o
opts.fn = f
opts.parseFn = f
return &opts
}

func (o *parseOptions) MetricSelectorFn() MetricSelectorFn {
return o.selectorFn
}

func (o *parseOptions) SetMetricSelectorFn(f MetricSelectorFn) ParseOptions {
opts := *o
opts.selectorFn = f
return &opts
}

Expand Down

0 comments on commit 6435114

Please sign in to comment.