app/vmselect/promql: return matrix instead of vector on subqueries to /api/v1/query like Prometheus does

This commit is contained in:
Aliaksandr Valialkin 2019-12-11 00:40:36 +02:00
parent 3c076544bf
commit caa4eb72d9
2 changed files with 69 additions and 15 deletions

View File

@ -486,21 +486,13 @@ func QueryHandler(w http.ResponseWriter, r *http.Request) error {
start = ct - queryOffset
}
if childQuery, windowStr, offsetStr := promql.IsMetricSelectorWithRollup(query); childQuery != "" {
var window int64
if len(windowStr) > 0 {
var err error
window, err = promql.PositiveDurationValue(windowStr, step)
window, err := parsePositiveDuration(windowStr, step)
if err != nil {
return err
return fmt.Errorf("cannot parse window: %s", err)
}
}
var offset int64
if len(offsetStr) > 0 {
var err error
offset, err = promql.DurationValue(offsetStr, step)
offset, err := parseDuration(offsetStr, step)
if err != nil {
return err
}
return fmt.Errorf("cannot parse offset: %s", err)
}
start -= offset
end := start
@ -511,6 +503,31 @@ func QueryHandler(w http.ResponseWriter, r *http.Request) error {
queryDuration.UpdateDuration(startTime)
return nil
}
if childQuery, windowStr, stepStr, offsetStr := promql.IsRollup(query); childQuery != "" {
newStep, err := parsePositiveDuration(stepStr, step)
if err != nil {
return fmt.Errorf("cannot parse step: %s", err)
}
if newStep > 0 {
step = newStep
}
window, err := parsePositiveDuration(windowStr, step)
if err != nil {
return fmt.Errorf("cannot parse window: %s", err)
}
offset, err := parseDuration(offsetStr, step)
if err != nil {
return fmt.Errorf("cannot parse offset: %s", err)
}
start -= offset
end := start
start = end - window
if err := queryRangeHandler(w, childQuery, start, end, step, r, ct); err != nil {
return err
}
queryDuration.UpdateDuration(startTime)
return nil
}
ec := promql.EvalConfig{
Start: start,
@ -532,6 +549,20 @@ func QueryHandler(w http.ResponseWriter, r *http.Request) error {
var queryDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/v1/query"}`)
func parseDuration(s string, step int64) (int64, error) {
if len(s) == 0 {
return 0, nil
}
return promql.DurationValue(s, step)
}
func parsePositiveDuration(s string, step int64) (int64, error) {
if len(s) == 0 {
return 0, nil
}
return promql.PositiveDurationValue(s, step)
}
// QueryRangeHandler processes /api/v1/query_range request.
//
// See https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
@ -555,6 +586,14 @@ func QueryRangeHandler(w http.ResponseWriter, r *http.Request) error {
if err != nil {
return err
}
if err := queryRangeHandler(w, query, start, end, step, r, ct); err != nil {
return err
}
queryRangeDuration.UpdateDuration(startTime)
return nil
}
func queryRangeHandler(w http.ResponseWriter, query string, start, end, step int64, r *http.Request, ct int64) error {
deadline := getDeadline(r)
mayCache := !getBool(r, "nocache")
lookbackDelta, err := getMaxLookback(r)
@ -599,7 +638,6 @@ func QueryRangeHandler(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Content-Type", "application/json")
WriteQueryRangeResponse(w, result)
queryRangeDuration.UpdateDuration(startTime)
return nil
}

View File

@ -1290,6 +1290,22 @@ func (p *parser) parseIdentExpr() (expr, error) {
}
}
// IsRollup verifies whether s is a rollup with non-empty window.
//
// It returns the wrapped query with the corresponding window, step and offset.
func IsRollup(s string) (childQuery string, window, step, offset string) {
expr, err := parsePromQLWithCache(s)
if err != nil {
return
}
re, ok := expr.(*rollupExpr)
if !ok || len(re.Window) == 0 {
return
}
wrappedQuery := re.Expr.AppendString(nil)
return string(wrappedQuery), re.Window, re.Step, re.Offset
}
// IsMetricSelectorWithRollup verifies whether s contains PromQL metric selector
// wrapped into rollup.
//