From e6a67476c299b904797d0d2534df112d06aa454b Mon Sep 17 00:00:00 2001 From: Brian Brazil Date: Wed, 19 Aug 2015 21:09:00 +0100 Subject: [PATCH] rules: Allow recorded rules expressions to be scalars. This is useful if you want to build up a constant metric, such as a set of alert thresholds that vary by label value. --- promql/parse.go | 5 ++++- promql/parse_test.go | 14 ++++++++++++-- rules/recording.go | 20 +++++++++++++++++--- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/promql/parse.go b/promql/parse.go index 6cfc5ea2b..35849dda8 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -1009,7 +1009,10 @@ func (p *parser) checkType(node Node) (typ ExprType) { } case *RecordStmt: - p.expectType(n.Expr, ExprVector, "record statement") + ty := p.checkType(n.Expr) + if ty != ExprVector && ty != ExprScalar { + p.errorf("record statement must have a valid expression of type vector or scalar but got %s", ty) + } case Expressions: for _, e := range n { diff --git a/promql/parse_test.go b/promql/parse_test.go index 24d581bfb..af761eccb 100644 --- a/promql/parse_test.go +++ b/promql/parse_test.go @@ -1207,10 +1207,20 @@ var testStatement = []struct { expected: Statements{}, }, { input: "foo = time()", - fail: true, + expected: Statements{ + &RecordStmt{ + Name: "foo", + Expr: &Call{Func: mustGetFunction("time")}, + Labels: nil, + }}, }, { input: "foo = 1", - fail: true, + expected: Statements{ + &RecordStmt{ + Name: "foo", + Expr: &NumberLiteral{1}, + Labels: nil, + }}, }, { input: "foo = bar[5m]", fail: true, diff --git a/rules/recording.go b/rules/recording.go index 4624e2941..bd96df672 100644 --- a/rules/recording.go +++ b/rules/recording.go @@ -48,9 +48,23 @@ func (rule RecordingRule) eval(timestamp clientmodel.Timestamp, engine *promql.E if err != nil { return nil, err } - vector, err := query.Exec().Vector() - if err != nil { - return nil, err + + result := query.Exec() + var vector promql.Vector + switch result.Value.(type) { + case promql.Vector: + vector, err = result.Vector() + if err != nil { + return nil, err + } + case *promql.Scalar: + scalar, err := result.Scalar() + if err != nil { + return nil, err + } + vector = promql.Vector{&promql.Sample{Value: scalar.Value, Timestamp: scalar.Timestamp}} + default: + return nil, fmt.Errorf("rule result is not a vector or scalar") } // Override the metric name and labels.