PromQL: AST: Make VectorSelector Children of MatrixSelector (#6590)

Make Vector selectors children of Matrix Selectors

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
This commit is contained in:
Tobias Guggenmos 2020-01-10 15:25:41 +01:00 committed by Brian Brazil
parent e7f7b6a06f
commit 64194f7d45
8 changed files with 185 additions and 172 deletions

View File

@ -107,14 +107,8 @@ type Call struct {
// MatrixSelector represents a Matrix selection.
type MatrixSelector struct {
Name string
Range time.Duration
Offset time.Duration
LabelMatchers []*labels.Matcher
// The unexpanded seriesSet populated at query preparation time.
unexpandedSeriesSet storage.SeriesSet
series []storage.Series
VectorSelector *VectorSelector
Range time.Duration
}
// SubqueryExpr represents a subquery.
@ -316,7 +310,9 @@ func Children(node Node) []Node {
return []Node{n.Expr}
case *UnaryExpr:
return []Node{n.Expr}
case *MatrixSelector, *NumberLiteral, *StringLiteral, *VectorSelector:
case *MatrixSelector:
return []Node{n.VectorSelector}
case *NumberLiteral, *StringLiteral, *VectorSelector:
// nothing to do
return []Node{}
default:

View File

@ -623,8 +623,8 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
if maxOffset < n.Range+subqOffset {
maxOffset = n.Range + subqOffset
}
if n.Offset+n.Range+subqOffset > maxOffset {
maxOffset = n.Offset + n.Range + subqOffset
if m := n.VectorSelector.Offset + n.Range + subqOffset; m > maxOffset {
maxOffset = m
}
}
return nil
@ -639,6 +639,11 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
var warnings storage.Warnings
// Whenever a MatrixSelector is evaluated this variable is set to the corresponding range.
// The evaluation of the VectorSelector inside then evaluates the given range and unsets
// the variable.
var evalRange time.Duration
Inspect(s.Expr, func(node Node, path []Node) error {
var set storage.SeriesSet
var wrn storage.Warnings
@ -658,7 +663,16 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
switch n := node.(type) {
case *VectorSelector:
params.Start = params.Start - durationMilliseconds(LookbackDelta)
if evalRange == 0 {
params.Start = params.Start - durationMilliseconds(LookbackDelta)
} else {
params.Range = durationMilliseconds(evalRange)
// For all matrix queries we want to ensure that we have (end-start) + range selected
// this way we have `range` data before the start time
params.Start = params.Start - durationMilliseconds(evalRange)
evalRange = 0
}
params.Func = extractFuncFromPath(path)
params.By, params.Grouping = extractGroupsFromPath(path)
if n.Offset > 0 {
@ -676,24 +690,7 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
n.unexpandedSeriesSet = set
case *MatrixSelector:
params.Func = extractFuncFromPath(path)
params.Range = durationMilliseconds(n.Range)
// For all matrix queries we want to ensure that we have (end-start) + range selected
// this way we have `range` data before the start time
params.Start = params.Start - durationMilliseconds(n.Range)
if n.Offset > 0 {
offsetMilliseconds := durationMilliseconds(n.Offset)
params.Start = params.Start - offsetMilliseconds
params.End = params.End - offsetMilliseconds
}
set, wrn, err = querier.Select(params, n.LabelMatchers...)
warnings = append(warnings, wrn...)
if err != nil {
level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
return err
}
n.unexpandedSeriesSet = set
evalRange = n.Range
}
return nil
})
@ -734,14 +731,7 @@ func extractGroupsFromPath(p []Node) (bool, []string) {
func checkForSeriesSetExpansion(ctx context.Context, expr Expr) {
switch e := expr.(type) {
case *MatrixSelector:
if e.series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
if err != nil {
panic(err)
} else {
e.series = series
}
}
checkForSeriesSetExpansion(ctx, e.VectorSelector)
case *VectorSelector:
if e.series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
@ -1000,12 +990,14 @@ func (ev *evaluator) rangeEval(f func([]Value, *EvalNodeHelper) Vector, exprs ..
func (ev *evaluator) evalSubquery(subq *SubqueryExpr) *MatrixSelector {
val := ev.eval(subq).(Matrix)
ms := &MatrixSelector{
Range: subq.Range,
Offset: subq.Offset,
series: make([]storage.Series, 0, len(val)),
Range: subq.Range,
VectorSelector: &VectorSelector{
Offset: subq.Offset,
series: make([]storage.Series, 0, len(val)),
},
}
for _, s := range val {
ms.series = append(ms.series, NewStorageSeries(s))
ms.VectorSelector.series = append(ms.VectorSelector.series, NewStorageSeries(s))
}
return ms
}
@ -1085,9 +1077,11 @@ func (ev *evaluator) eval(expr Expr) Value {
}
sel := e.Args[matrixArgIndex].(*MatrixSelector)
selVS := sel.VectorSelector
checkForSeriesSetExpansion(ev.ctx, sel)
mat := make(Matrix, 0, len(sel.series)) // Output matrix.
offset := durationMilliseconds(sel.Offset)
mat := make(Matrix, 0, len(selVS.series)) // Output matrix.
offset := durationMilliseconds(selVS.Offset)
selRange := durationMilliseconds(sel.Range)
stepRange := selRange
if stepRange > ev.interval {
@ -1100,17 +1094,17 @@ func (ev *evaluator) eval(expr Expr) Value {
enh := &EvalNodeHelper{out: make(Vector, 0, 1)}
// Process all the calls for one time series at a time.
it := storage.NewBuffer(selRange)
for i, s := range sel.series {
for i, s := range selVS.series {
points = points[:0]
it.Reset(s.Iterator())
ss := Series{
// For all range vector functions, the only change to the
// output labels is dropping the metric name so just do
// it once here.
Metric: dropMetricName(sel.series[i].Labels()),
Metric: dropMetricName(selVS.series[i].Labels()),
Points: getPointSlice(numSteps),
}
inMatrix[0].Metric = sel.series[i].Labels()
inMatrix[0].Metric = selVS.series[i].Labels()
for ts, step := ev.startTimestamp, -1; ts <= ev.endTimestamp; ts += ev.interval {
step++
// Set the non-matrix arguments.
@ -1409,20 +1403,22 @@ func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix {
checkForSeriesSetExpansion(ev.ctx, node)
var (
offset = durationMilliseconds(node.Offset)
offset = durationMilliseconds(node.VectorSelector.Offset)
maxt = ev.startTimestamp - offset
mint = maxt - durationMilliseconds(node.Range)
matrix = make(Matrix, 0, len(node.series))
matrix = make(Matrix, 0, len(node.VectorSelector.series))
)
it := storage.NewBuffer(durationMilliseconds(node.Range))
for i, s := range node.series {
series := node.VectorSelector.series
for i, s := range series {
if err := contextDone(ev.ctx, "expression evaluation"); err != nil {
ev.error(err)
}
it.Reset(s.Iterator())
ss := Series{
Metric: node.series[i].Labels(),
Metric: series[i].Labels(),
}
ss.Points = ev.matrixIterSlice(it, mint, maxt, getPointSlice(16))

View File

@ -67,8 +67,8 @@ func extrapolatedRate(vals []Value, args Expressions, enh *EvalNodeHelper, isCou
var (
samples = vals[0].(Matrix)[0]
rangeStart = enh.ts - durationMilliseconds(ms.Range+ms.Offset)
rangeEnd = enh.ts - durationMilliseconds(ms.Offset)
rangeStart = enh.ts - durationMilliseconds(ms.Range+ms.VectorSelector.Offset)
rangeEnd = enh.ts - durationMilliseconds(ms.VectorSelector.Offset)
)
// No sense in trying to compute a rate without at least two points. Drop
@ -1243,7 +1243,7 @@ func createLabelsForAbsentFunction(expr Expr) labels.Labels {
case *VectorSelector:
lm = n.LabelMatchers
case *MatrixSelector:
lm = n.LabelMatchers
lm = n.VectorSelector.LabelMatchers
default:
return m
}

View File

@ -384,9 +384,7 @@ matrix_selector : expr LEFT_BRACKET duration RIGHT_BRACKET
yylex.(*parser).errorf("no offset modifiers allowed before range")
}
$$ = &MatrixSelector{
Name: vs.Name,
Offset: vs.Offset,
LabelMatchers: vs.LabelMatchers,
VectorSelector: vs,
Range: $3,
}
}

View File

@ -184,7 +184,7 @@ const yyEofCode = 1
const yyErrCode = 2
const yyInitialStackSize = 16
//line promql/generated_parser.y:641
//line promql/generated_parser.y:639
//line yacctab:1
var yyExca = [...]int{
@ -1119,15 +1119,13 @@ yydefault:
yylex.(*parser).errorf("no offset modifiers allowed before range")
}
yyVAL.node = &MatrixSelector{
Name: vs.Name,
Offset: vs.Offset,
LabelMatchers: vs.LabelMatchers,
Range: yyDollar[3].duration,
VectorSelector: vs,
Range: yyDollar[3].duration,
}
}
case 67:
yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:396
//line promql/generated_parser.y:394
{
yyVAL.node = &SubqueryExpr{
Expr: yyDollar[1].node.(Expr),
@ -1137,31 +1135,31 @@ yydefault:
}
case 68:
yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:404
//line promql/generated_parser.y:402
{
yylex.(*parser).unexpected("subquery selector", "\"]\"")
}
case 69:
yyDollar = yyS[yypt-5 : yypt+1]
//line promql/generated_parser.y:406
//line promql/generated_parser.y:404
{
yylex.(*parser).unexpected("subquery selector", "duration or \"]\"")
}
case 70:
yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:408
//line promql/generated_parser.y:406
{
yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"")
}
case 71:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:410
//line promql/generated_parser.y:408
{
yylex.(*parser).unexpected("subquery selector", "duration")
}
case 72:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:420
//line promql/generated_parser.y:418
{
if nl, ok := yyDollar[2].node.(*NumberLiteral); ok {
if yyDollar[1].item.Typ == SUB {
@ -1174,164 +1172,164 @@ yydefault:
}
case 73:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:437
//line promql/generated_parser.y:435
{
yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, yyDollar[2].matchers)
}
case 74:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:439
//line promql/generated_parser.y:437
{
yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, nil)
}
case 75:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:441
//line promql/generated_parser.y:439
{
yyVAL.node = yylex.(*parser).newVectorSelector("", yyDollar[1].matchers)
}
case 76:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:445
//line promql/generated_parser.y:443
{
yyVAL.matchers = yyDollar[2].matchers
}
case 77:
yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:447
//line promql/generated_parser.y:445
{
yyVAL.matchers = yyDollar[2].matchers
}
case 78:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:449
//line promql/generated_parser.y:447
{
yyVAL.matchers = []*labels.Matcher{}
}
case 79:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:454
//line promql/generated_parser.y:452
{
yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher)
}
case 80:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:456
//line promql/generated_parser.y:454
{
yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher}
}
case 81:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:458
//line promql/generated_parser.y:456
{
yylex.(*parser).unexpected("label matching", "\",\" or \"}\"")
}
case 82:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:462
//line promql/generated_parser.y:460
{
yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item)
}
case 83:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:464
//line promql/generated_parser.y:462
{
yylex.(*parser).unexpected("label matching", "string")
}
case 84:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:466
//line promql/generated_parser.y:464
{
yylex.(*parser).unexpected("label matching", "label matching operator")
}
case 85:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:468
//line promql/generated_parser.y:466
{
yylex.(*parser).unexpected("label matching", "identifier or \"}\"")
}
case 86:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:476
//line promql/generated_parser.y:474
{
yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val})
sort.Sort(yyVAL.labels)
}
case 87:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:478
//line promql/generated_parser.y:476
{
yyVAL.labels = yyDollar[1].labels
}
case 90:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:485
//line promql/generated_parser.y:483
{
yyVAL.labels = labels.New(yyDollar[2].labels...)
}
case 91:
yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:487
//line promql/generated_parser.y:485
{
yyVAL.labels = labels.New(yyDollar[2].labels...)
}
case 92:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:489
//line promql/generated_parser.y:487
{
yyVAL.labels = labels.New()
}
case 93:
yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:491
//line promql/generated_parser.y:489
{
yyVAL.labels = labels.New()
}
case 94:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:495
//line promql/generated_parser.y:493
{
yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label)
}
case 95:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:497
//line promql/generated_parser.y:495
{
yyVAL.labels = []labels.Label{yyDollar[1].label}
}
case 96:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:499
//line promql/generated_parser.y:497
{
yylex.(*parser).unexpected("label set", "\",\" or \"}\"")
}
case 97:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:504
//line promql/generated_parser.y:502
{
yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)}
}
case 98:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:506
//line promql/generated_parser.y:504
{
yylex.(*parser).unexpected("label set", "string")
}
case 99:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:508
//line promql/generated_parser.y:506
{
yylex.(*parser).unexpected("label set", "\"=\"")
}
case 100:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:510
//line promql/generated_parser.y:508
{
yylex.(*parser).unexpected("label set", "identifier or \"}\"")
}
case 101:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:518
//line promql/generated_parser.y:516
{
yylex.(*parser).generatedParserResult = &seriesDescription{
labels: yyDollar[1].labels,
@ -1340,37 +1338,37 @@ yydefault:
}
case 102:
yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:527
//line promql/generated_parser.y:525
{
yyVAL.series = []sequenceValue{}
}
case 103:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:529
//line promql/generated_parser.y:527
{
yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...)
}
case 104:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:531
//line promql/generated_parser.y:529
{
yyVAL.series = yyDollar[1].series
}
case 105:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:533
//line promql/generated_parser.y:531
{
yylex.(*parser).unexpected("series values", "")
}
case 106:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:537
//line promql/generated_parser.y:535
{
yyVAL.series = []sequenceValue{{omitted: true}}
}
case 107:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:539
//line promql/generated_parser.y:537
{
yyVAL.series = []sequenceValue{}
for i := uint64(0); i < yyDollar[3].uint; i++ {
@ -1379,13 +1377,13 @@ yydefault:
}
case 108:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:546
//line promql/generated_parser.y:544
{
yyVAL.series = []sequenceValue{{value: yyDollar[1].float}}
}
case 109:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:548
//line promql/generated_parser.y:546
{
yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[3].uint; i++ {
@ -1394,7 +1392,7 @@ yydefault:
}
case 110:
yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:555
//line promql/generated_parser.y:553
{
yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[4].uint; i++ {
@ -1404,7 +1402,7 @@ yydefault:
}
case 111:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:565
//line promql/generated_parser.y:563
{
if yyDollar[1].item.Val != "stale" {
yylex.(*parser).unexpected("series values", "number or \"stale\"")
@ -1413,31 +1411,31 @@ yydefault:
}
case 154:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:595
//line promql/generated_parser.y:593
{
yyVAL.node = &NumberLiteral{yyDollar[1].float}
}
case 155:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:597
//line promql/generated_parser.y:595
{
yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val)
}
case 156:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:599
//line promql/generated_parser.y:597
{
yyVAL.float = yyDollar[2].float
}
case 157:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:600
//line promql/generated_parser.y:598
{
yyVAL.float = -yyDollar[2].float
}
case 158:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:604
//line promql/generated_parser.y:602
{
var err error
yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64)
@ -1447,7 +1445,7 @@ yydefault:
}
case 159:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:614
//line promql/generated_parser.y:612
{
var err error
yyVAL.duration, err = parseDuration(yyDollar[1].item.Val)
@ -1457,25 +1455,25 @@ yydefault:
}
case 160:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:624
//line promql/generated_parser.y:622
{
yyVAL.node = &StringLiteral{yyDollar[1].string}
}
case 161:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:626
//line promql/generated_parser.y:624
{
yyVAL.string = yylex.(*parser).unquoteString(yyDollar[1].item.Val)
}
case 162:
yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:633
//line promql/generated_parser.y:631
{
yyVAL.duration = 0
}
case 164:
yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:637
//line promql/generated_parser.y:635
{
yyVAL.strings = nil
}

View File

@ -504,8 +504,10 @@ func (p *parser) checkType(node Node) (typ ValueType) {
if ty != ValueTypeVector {
p.errorf("subquery is only allowed on instant vector, got %s in %q instead", ty, n.String())
}
case *MatrixSelector:
p.checkType(n.VectorSelector)
case *NumberLiteral, *MatrixSelector, *StringLiteral, *VectorSelector:
case *NumberLiteral, *StringLiteral, *VectorSelector:
// Nothing to do for terminals.
default:
@ -581,7 +583,7 @@ func (p *parser) addOffset(e Node, offset time.Duration) {
case *VectorSelector:
offsetp = &s.Offset
case *MatrixSelector:
offsetp = &s.Offset
offsetp = &s.VectorSelector.Offset
case *SubqueryExpr:
offsetp = &s.Offset
default:

View File

@ -1028,63 +1028,76 @@ var testExpr = []struct {
{
input: "test[5s]",
expected: &MatrixSelector{
Name: "test",
Offset: 0,
Range: 5 * time.Second,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 0,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * time.Second,
},
}, {
input: "test[5m]",
expected: &MatrixSelector{
Name: "test",
Offset: 0,
Range: 5 * time.Minute,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 0,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * time.Minute,
},
}, {
input: "test[5h] OFFSET 5m",
expected: &MatrixSelector{
Name: "test",
Offset: 5 * time.Minute,
Range: 5 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 5 * time.Minute,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * time.Hour,
},
}, {
input: "test[5d] OFFSET 10s",
expected: &MatrixSelector{
Name: "test",
Offset: 10 * time.Second,
Range: 5 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 10 * time.Second,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * 24 * time.Hour,
},
}, {
input: "test[5w] offset 2w",
expected: &MatrixSelector{
Name: "test",
Offset: 14 * 24 * time.Hour,
Range: 5 * 7 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 14 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * 7 * 24 * time.Hour,
},
}, {
input: `test{a="b"}[5y] OFFSET 3d`,
expected: &MatrixSelector{
Name: "test",
Offset: 3 * 24 * time.Hour,
Range: 5 * 365 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "a", "b"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
VectorSelector: &VectorSelector{
Name: "test",
Offset: 3 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "a", "b"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
},
Range: 5 * 365 * 24 * time.Hour,
},
}, {
input: `foo[5mm]`,
@ -1378,9 +1391,11 @@ var testExpr = []struct {
Func: mustGetFunction("rate"),
Args: Expressions{
&MatrixSelector{
Name: "some_metric",
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"),
VectorSelector: &VectorSelector{
Name: "some_metric",
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"),
},
},
Range: 5 * time.Minute,
},
@ -1535,12 +1550,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"),
Args: Expressions{
&MatrixSelector{
Name: "foo",
Range: 2 * time.Second,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
VectorSelector: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
},
Range: 2 * time.Second,
},
},
},
@ -1560,12 +1577,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"),
Args: Expressions{
&MatrixSelector{
Name: "foo",
Range: 2 * time.Second,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
VectorSelector: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
},
Range: 2 * time.Second,
},
},
},
@ -1587,12 +1606,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"),
Args: Expressions{
&MatrixSelector{
Name: "foo",
Range: 2 * time.Second,
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
VectorSelector: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
},
Range: 2 * time.Second,
},
},
},

View File

@ -112,14 +112,16 @@ func (node *Call) String() string {
}
func (node *MatrixSelector) String() string {
vecSelector := &VectorSelector{
Name: node.Name,
LabelMatchers: node.LabelMatchers,
}
// Copy the Vector selector before changing the offset
var vecSelector VectorSelector = *node.VectorSelector
offset := ""
if node.Offset != time.Duration(0) {
offset = fmt.Sprintf(" offset %s", model.Duration(node.Offset))
if vecSelector.Offset != time.Duration(0) {
offset = fmt.Sprintf(" offset %s", model.Duration(vecSelector.Offset))
}
// Do not print the offset twice.
vecSelector.Offset = 0
return fmt.Sprintf("%s[%s]%s", vecSelector.String(), model.Duration(node.Range), offset)
}