mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-27 14:39:40 -08:00
Merge "Allow reversing vector and scalar arguments in binops."
This commit is contained in:
commit
95bc920f5f
|
@ -195,11 +195,12 @@ type (
|
||||||
vector VectorNode
|
vector VectorNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// VectorArithExpr represents an arithmetic expression of
|
// VectorArithExpr represents an arithmetic expression of vector type. At
|
||||||
// vector type.
|
// least one of the two operand Nodes must be a VectorNode. The other may be
|
||||||
|
// a VectorNode or ScalarNode. Both criteria are checked at runtime.
|
||||||
VectorArithExpr struct {
|
VectorArithExpr struct {
|
||||||
opType BinOpType
|
opType BinOpType
|
||||||
lhs VectorNode
|
lhs Node
|
||||||
rhs Node
|
rhs Node
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -639,9 +640,20 @@ func labelsEqual(labels1, labels2 clientmodel.Metric) bool {
|
||||||
// Eval implements the VectorNode interface and returns the result of
|
// Eval implements the VectorNode interface and returns the result of
|
||||||
// the expression.
|
// the expression.
|
||||||
func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
|
func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
|
||||||
lhs := node.lhs.Eval(timestamp, view)
|
|
||||||
result := Vector{}
|
result := Vector{}
|
||||||
if node.rhs.Type() == SCALAR {
|
if node.lhs.Type() == SCALAR && node.rhs.Type() == VECTOR {
|
||||||
|
lhs := node.lhs.(ScalarNode).Eval(timestamp, view)
|
||||||
|
rhs := node.rhs.(VectorNode).Eval(timestamp, view)
|
||||||
|
for _, rhsSample := range rhs {
|
||||||
|
value, keep := evalVectorBinop(node.opType, lhs, rhsSample.Value)
|
||||||
|
if keep {
|
||||||
|
rhsSample.Value = value
|
||||||
|
result = append(result, rhsSample)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} else if node.lhs.Type() == VECTOR && node.rhs.Type() == SCALAR {
|
||||||
|
lhs := node.lhs.(VectorNode).Eval(timestamp, view)
|
||||||
rhs := node.rhs.(ScalarNode).Eval(timestamp, view)
|
rhs := node.rhs.(ScalarNode).Eval(timestamp, view)
|
||||||
for _, lhsSample := range lhs {
|
for _, lhsSample := range lhs {
|
||||||
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhs)
|
value, keep := evalVectorBinop(node.opType, lhsSample.Value, rhs)
|
||||||
|
@ -651,7 +663,8 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAda
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
} else if node.rhs.Type() == VECTOR {
|
} else if node.lhs.Type() == VECTOR && node.rhs.Type() == VECTOR {
|
||||||
|
lhs := node.lhs.(VectorNode).Eval(timestamp, view)
|
||||||
rhs := node.rhs.(VectorNode).Eval(timestamp, view)
|
rhs := node.rhs.(VectorNode).Eval(timestamp, view)
|
||||||
for _, lhsSample := range lhs {
|
for _, lhsSample := range lhs {
|
||||||
for _, rhsSample := range rhs {
|
for _, rhsSample := range rhs {
|
||||||
|
@ -804,9 +817,6 @@ func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) {
|
||||||
if !nodesHaveTypes(Nodes{lhs, rhs}, []ExprType{SCALAR, VECTOR}) {
|
if !nodesHaveTypes(Nodes{lhs, rhs}, []ExprType{SCALAR, VECTOR}) {
|
||||||
return nil, errors.New("binary operands must be of vector or scalar type")
|
return nil, errors.New("binary operands must be of vector or scalar type")
|
||||||
}
|
}
|
||||||
if lhs.Type() == SCALAR && rhs.Type() == VECTOR {
|
|
||||||
return nil, errors.New("left side of vector binary operation must be of vector type")
|
|
||||||
}
|
|
||||||
|
|
||||||
if opType == AND || opType == OR {
|
if opType == AND || opType == OR {
|
||||||
if lhs.Type() == SCALAR || rhs.Type() == SCALAR {
|
if lhs.Type() == SCALAR || rhs.Type() == SCALAR {
|
||||||
|
@ -817,7 +827,7 @@ func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) {
|
||||||
if lhs.Type() == VECTOR || rhs.Type() == VECTOR {
|
if lhs.Type() == VECTOR || rhs.Type() == VECTOR {
|
||||||
return &VectorArithExpr{
|
return &VectorArithExpr{
|
||||||
opType: opType,
|
opType: opType,
|
||||||
lhs: lhs.(VectorNode),
|
lhs: lhs,
|
||||||
rhs: rhs,
|
rhs: rhs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,22 @@ func TestExpressions(t *testing.T) {
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
|
}, {
|
||||||
|
expr: `2 - SUM(http_requests) BY (job)`,
|
||||||
|
output: []string{
|
||||||
|
`http_requests{job="api-server"} => -998 @[%v]`,
|
||||||
|
`http_requests{job="app-server"} => -2598 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 8,
|
||||||
|
}, {
|
||||||
|
expr: `1000 / SUM(http_requests) BY (job)`,
|
||||||
|
output: []string{
|
||||||
|
`http_requests{job="api-server"} => 1 @[%v]`,
|
||||||
|
`http_requests{job="app-server"} => 0.38461538461538464 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) - 2`,
|
expr: `SUM(http_requests) BY (job) - 2`,
|
||||||
output: []string{
|
output: []string{
|
||||||
|
@ -240,6 +256,13 @@ func TestExpressions(t *testing.T) {
|
||||||
},
|
},
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 8,
|
intervalRanges: 8,
|
||||||
|
}, {
|
||||||
|
expr: `1000 < SUM(http_requests) BY (job)`,
|
||||||
|
output: []string{
|
||||||
|
`http_requests{job="app-server"} => 1000 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 8,
|
||||||
}, {
|
}, {
|
||||||
expr: `SUM(http_requests) BY (job) <= 1000`,
|
expr: `SUM(http_requests) BY (job) <= 1000`,
|
||||||
output: []string{
|
output: []string{
|
||||||
|
@ -398,14 +421,14 @@ func TestExpressions(t *testing.T) {
|
||||||
// Empty expressions shouldn"t parse.
|
// Empty expressions shouldn"t parse.
|
||||||
expr: ``,
|
expr: ``,
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
}, {
|
|
||||||
// Subtracting a vector from a scalar is not supported.
|
|
||||||
expr: `1 - http_requests`,
|
|
||||||
shouldFail: true,
|
|
||||||
}, {
|
}, {
|
||||||
// Interval durations can"t be in quotes.
|
// Interval durations can"t be in quotes.
|
||||||
expr: `http_requests["1m"]`,
|
expr: `http_requests["1m"]`,
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
|
}, {
|
||||||
|
// Binop arguments need to be scalar or vector.
|
||||||
|
expr: `http_requests - http_requests[1m]`,
|
||||||
|
shouldFail: true,
|
||||||
}, {
|
}, {
|
||||||
expr: `http_requests{group!="canary"}`,
|
expr: `http_requests{group!="canary"}`,
|
||||||
output: []string{
|
output: []string{
|
||||||
|
|
Loading…
Reference in a new issue