mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-11 13:57:36 -08:00
Switch promql types to common/model
This commit is contained in:
parent
e061595352
commit
d6b8da8d43
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
|
@ -60,11 +60,11 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/prometheus/common/expfmt",
|
||||
"Rev": "675b18b12eb9d452d0377f1688d62e724f15b882"
|
||||
"Rev": "7cd9f43750daf997c60f33f46680780067410f28"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/prometheus/common/model",
|
||||
"Rev": "675b18b12eb9d452d0377f1688d62e724f15b882"
|
||||
"Rev": "7cd9f43750daf997c60f33f46680780067410f28"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/prometheus/client_model/go",
|
||||
|
|
8
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
8
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
|
@ -278,8 +278,8 @@ func (e ValueType) String() string {
|
|||
|
||||
// Scalar is a scalar value evaluated at the set timestamp.
|
||||
type Scalar struct {
|
||||
Value SampleValue
|
||||
Timestamp Time
|
||||
Value SampleValue `json:"value"`
|
||||
Timestamp Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (s Scalar) String() string {
|
||||
|
@ -311,8 +311,8 @@ func (s *Scalar) UnmarshalJSON(b []byte) error {
|
|||
|
||||
// String is a string value evaluated at the set timestamp.
|
||||
type String struct {
|
||||
Value string
|
||||
Timestamp Time
|
||||
Value string `json:"value"`
|
||||
Timestamp Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (s *String) String() string {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
@ -88,45 +87,13 @@ func (*AlertStmt) stmt() {}
|
|||
func (*EvalStmt) stmt() {}
|
||||
func (*RecordStmt) stmt() {}
|
||||
|
||||
// ExprType is the type an evaluated expression returns.
|
||||
type ExprType int
|
||||
|
||||
const (
|
||||
ExprNone ExprType = iota
|
||||
ExprScalar
|
||||
ExprVector
|
||||
ExprMatrix
|
||||
ExprString
|
||||
)
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (et ExprType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(et.String())
|
||||
}
|
||||
|
||||
func (e ExprType) String() string {
|
||||
switch e {
|
||||
case ExprNone:
|
||||
return "<ExprNone>"
|
||||
case ExprScalar:
|
||||
return "scalar"
|
||||
case ExprVector:
|
||||
return "vector"
|
||||
case ExprMatrix:
|
||||
return "matrix"
|
||||
case ExprString:
|
||||
return "string"
|
||||
}
|
||||
panic("promql.ExprType.String: unhandled expression type")
|
||||
}
|
||||
|
||||
// Expr is a generic interface for all expression types.
|
||||
type Expr interface {
|
||||
Node
|
||||
|
||||
// Type returns the type the expression evaluates to. It does not perform
|
||||
// in-depth checks as this is done at parsing-time.
|
||||
Type() ExprType
|
||||
Type() model.ValueType
|
||||
// expr ensures that no other types accidentally implement the interface.
|
||||
expr()
|
||||
}
|
||||
|
@ -167,7 +134,7 @@ type MatrixSelector struct {
|
|||
|
||||
// The series iterators are populated at query analysis time.
|
||||
iterators map[model.Fingerprint]local.SeriesIterator
|
||||
metrics map[model.Fingerprint]model.COWMetric
|
||||
metrics map[model.Fingerprint]metric.Metric
|
||||
}
|
||||
|
||||
// NumberLiteral represents a number.
|
||||
|
@ -201,23 +168,23 @@ type VectorSelector struct {
|
|||
|
||||
// The series iterators are populated at query analysis time.
|
||||
iterators map[model.Fingerprint]local.SeriesIterator
|
||||
metrics map[model.Fingerprint]model.COWMetric
|
||||
metrics map[model.Fingerprint]metric.Metric
|
||||
}
|
||||
|
||||
func (e *AggregateExpr) Type() ExprType { return ExprVector }
|
||||
func (e *Call) Type() ExprType { return e.Func.ReturnType }
|
||||
func (e *MatrixSelector) Type() ExprType { return ExprMatrix }
|
||||
func (e *NumberLiteral) Type() ExprType { return ExprScalar }
|
||||
func (e *ParenExpr) Type() ExprType { return e.Expr.Type() }
|
||||
func (e *StringLiteral) Type() ExprType { return ExprString }
|
||||
func (e *UnaryExpr) Type() ExprType { return e.Expr.Type() }
|
||||
func (e *VectorSelector) Type() ExprType { return ExprVector }
|
||||
func (e *AggregateExpr) Type() model.ValueType { return model.ValVector }
|
||||
func (e *Call) Type() model.ValueType { return e.Func.ReturnType }
|
||||
func (e *MatrixSelector) Type() model.ValueType { return model.ValMatrix }
|
||||
func (e *NumberLiteral) Type() model.ValueType { return model.ValScalar }
|
||||
func (e *ParenExpr) Type() model.ValueType { return e.Expr.Type() }
|
||||
func (e *StringLiteral) Type() model.ValueType { return model.ValString }
|
||||
func (e *UnaryExpr) Type() model.ValueType { return e.Expr.Type() }
|
||||
func (e *VectorSelector) Type() model.ValueType { return model.ValVector }
|
||||
|
||||
func (e *BinaryExpr) Type() ExprType {
|
||||
if e.LHS.Type() == ExprScalar && e.RHS.Type() == ExprScalar {
|
||||
return ExprScalar
|
||||
func (e *BinaryExpr) Type() model.ValueType {
|
||||
if e.LHS.Type() == model.ValScalar && e.RHS.Type() == model.ValScalar {
|
||||
return model.ValScalar
|
||||
}
|
||||
return ExprVector
|
||||
return model.ValVector
|
||||
}
|
||||
|
||||
func (*AggregateExpr) expr() {}
|
||||
|
|
314
promql/engine.go
314
promql/engine.go
|
@ -14,12 +14,10 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -31,114 +29,70 @@ import (
|
|||
"github.com/prometheus/prometheus/util/stats"
|
||||
)
|
||||
|
||||
// SampleStream is a stream of Values belonging to an attached COWMetric.
|
||||
type SampleStream struct {
|
||||
Metric model.COWMetric `json:"metric"`
|
||||
Values []model.SamplePair `json:"values"`
|
||||
// sampleStream is a stream of Values belonging to an attached COWMetric.
|
||||
type sampleStream struct {
|
||||
Metric metric.Metric
|
||||
Values []model.SamplePair
|
||||
}
|
||||
|
||||
// Sample is a single sample belonging to a COWMetric.
|
||||
type Sample struct {
|
||||
Metric model.COWMetric `json:"metric"`
|
||||
Value model.SampleValue `json:"value"`
|
||||
Timestamp model.Time `json:"timestamp"`
|
||||
// sample is a single sample belonging to a COWMetric.
|
||||
type sample struct {
|
||||
Metric metric.Metric
|
||||
Value model.SampleValue
|
||||
Timestamp model.Time
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (s *Sample) MarshalJSON() ([]byte, error) {
|
||||
v := struct {
|
||||
Metric model.COWMetric `json:"metric"`
|
||||
Value model.SamplePair `json:"value"`
|
||||
}{
|
||||
Metric: s.Metric,
|
||||
Value: model.SamplePair{
|
||||
Timestamp: s.Timestamp,
|
||||
Value: s.Value,
|
||||
},
|
||||
}
|
||||
|
||||
return json.Marshal(&v)
|
||||
}
|
||||
|
||||
// Scalar is a scalar value evaluated at the set timestamp.
|
||||
type Scalar struct {
|
||||
Value model.SampleValue `json:"value"`
|
||||
Timestamp model.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (s *Scalar) String() string {
|
||||
return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp)
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (s *Scalar) MarshalJSON() ([]byte, error) {
|
||||
v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64)
|
||||
return json.Marshal([]interface{}{s.Timestamp, string(v)})
|
||||
}
|
||||
|
||||
// String is a string value evaluated at the set timestamp.
|
||||
type String struct {
|
||||
Value string `json:"value"`
|
||||
Timestamp model.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (s *String) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]interface{}{s.Timestamp, s.Value})
|
||||
}
|
||||
|
||||
func (s *String) String() string {
|
||||
return s.Value
|
||||
}
|
||||
|
||||
// Vector is basically only an alias for model.Samples, but the
|
||||
// vector is basically only an alias for model.Samples, but the
|
||||
// contract is that in a Vector, all Samples have the same timestamp.
|
||||
type Vector []*Sample
|
||||
type vector []*sample
|
||||
|
||||
// Matrix is a slice of SampleStreams that implements sort.Interface and
|
||||
func (vector) Type() model.ValueType { return model.ValVector }
|
||||
func (vec vector) String() string { return vec.value().String() }
|
||||
|
||||
func (vec vector) value() model.Vector {
|
||||
val := make(model.Vector, len(vec))
|
||||
for i, s := range vec {
|
||||
val[i] = &model.Sample{
|
||||
Metric: s.Metric.Copy().Metric,
|
||||
Value: s.Value,
|
||||
Timestamp: s.Timestamp,
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// matrix is a slice of SampleStreams that implements sort.Interface and
|
||||
// has a String method.
|
||||
type Matrix []*SampleStream
|
||||
type matrix []*sampleStream
|
||||
|
||||
// Len implements sort.Interface.
|
||||
func (matrix Matrix) Len() int {
|
||||
return len(matrix)
|
||||
func (matrix) Type() model.ValueType { return model.ValMatrix }
|
||||
func (mat matrix) String() string { return mat.value().String() }
|
||||
|
||||
func (mat matrix) value() model.Matrix {
|
||||
val := make(model.Matrix, len(mat))
|
||||
for i, ss := range mat {
|
||||
val[i] = &model.SampleStream{
|
||||
Metric: ss.Metric.Copy().Metric,
|
||||
Values: ss.Values,
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Less implements sort.Interface.
|
||||
func (matrix Matrix) Less(i, j int) bool {
|
||||
return matrix[i].Metric.String() < matrix[j].Metric.String()
|
||||
}
|
||||
|
||||
// Swap implements sort.Interface.
|
||||
func (matrix Matrix) Swap(i, j int) {
|
||||
matrix[i], matrix[j] = matrix[j], matrix[i]
|
||||
}
|
||||
|
||||
// Value is a generic interface for values resulting from a query evaluation.
|
||||
type Value interface {
|
||||
Type() ExprType
|
||||
String() string
|
||||
}
|
||||
|
||||
func (Matrix) Type() ExprType { return ExprMatrix }
|
||||
func (Vector) Type() ExprType { return ExprVector }
|
||||
func (*Scalar) Type() ExprType { return ExprScalar }
|
||||
func (*String) Type() ExprType { return ExprString }
|
||||
|
||||
// Result holds the resulting value of an execution or an error
|
||||
// if any occurred.
|
||||
type Result struct {
|
||||
Err error
|
||||
Value Value
|
||||
Value model.Value
|
||||
}
|
||||
|
||||
// Vector returns a vector if the result value is one. An error is returned if
|
||||
// the result was an error or the result value is not a vector.
|
||||
func (r *Result) Vector() (Vector, error) {
|
||||
func (r *Result) Vector() (model.Vector, error) {
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
}
|
||||
v, ok := r.Value.(Vector)
|
||||
v, ok := r.Value.(model.Vector)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("query result is not a vector")
|
||||
}
|
||||
|
@ -147,11 +101,11 @@ func (r *Result) Vector() (Vector, error) {
|
|||
|
||||
// Matrix returns a matrix. An error is returned if
|
||||
// the result was an error or the result value is not a matrix.
|
||||
func (r *Result) Matrix() (Matrix, error) {
|
||||
func (r *Result) Matrix() (model.Matrix, error) {
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
}
|
||||
v, ok := r.Value.(Matrix)
|
||||
v, ok := r.Value.(model.Matrix)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("query result is not a matrix")
|
||||
}
|
||||
|
@ -160,11 +114,11 @@ func (r *Result) Matrix() (Matrix, error) {
|
|||
|
||||
// Scalar returns a scalar value. An error is returned if
|
||||
// the result was an error or the result value is not a scalar.
|
||||
func (r *Result) Scalar() (*Scalar, error) {
|
||||
func (r *Result) Scalar() (*model.Scalar, error) {
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
}
|
||||
v, ok := r.Value.(*Scalar)
|
||||
v, ok := r.Value.(*model.Scalar)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("query result is not a scalar")
|
||||
}
|
||||
|
@ -326,7 +280,7 @@ func (ng *Engine) NewRangeQuery(qs string, start, end model.Time, interval time.
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if expr.Type() != ExprVector && expr.Type() != ExprScalar {
|
||||
if expr.Type() != model.ValVector && expr.Type() != model.ValScalar {
|
||||
return nil, fmt.Errorf("invalid expression type %q for range query, must be scalar or vector", expr.Type())
|
||||
}
|
||||
qry := ng.newQuery(expr, start, end, interval)
|
||||
|
@ -372,7 +326,7 @@ func (ng *Engine) newTestQuery(f func(context.Context) error) Query {
|
|||
//
|
||||
// At this point per query only one EvalStmt is evaluated. Alert and record
|
||||
// statements are not handled by the Engine.
|
||||
func (ng *Engine) exec(q *query) (Value, error) {
|
||||
func (ng *Engine) exec(q *query) (model.Value, error) {
|
||||
ctx, cancel := context.WithTimeout(q.ng.baseCtx, ng.options.Timeout)
|
||||
q.cancel = cancel
|
||||
|
||||
|
@ -409,7 +363,7 @@ func (ng *Engine) exec(q *query) (Value, error) {
|
|||
}
|
||||
|
||||
// execEvalStmt evaluates the expression of an evaluation statement for the given time range.
|
||||
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, error) {
|
||||
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (model.Value, error) {
|
||||
prepareTimer := query.stats.GetTimer(stats.TotalQueryPreparationTime).Start()
|
||||
analyzeTimer := query.stats.GetTimer(stats.QueryAnalysisTime).Start()
|
||||
|
||||
|
@ -452,13 +406,22 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Turn matrix and vector types with protected metrics into
|
||||
// model.* types.
|
||||
switch v := val.(type) {
|
||||
case vector:
|
||||
val = v.value()
|
||||
case matrix:
|
||||
val = v.value()
|
||||
}
|
||||
|
||||
evalTimer.Stop()
|
||||
return val, nil
|
||||
}
|
||||
numSteps := int(s.End.Sub(s.Start) / s.Interval)
|
||||
|
||||
// Range evaluation.
|
||||
sampleStreams := map[model.Fingerprint]*SampleStream{}
|
||||
sampleStreams := map[model.Fingerprint]*sampleStream{}
|
||||
for ts := s.Start; !ts.After(s.End); ts = ts.Add(s.Interval) {
|
||||
|
||||
if err := contextDone(ctx, "range evaluation"); err != nil {
|
||||
|
@ -475,24 +438,24 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
|
|||
}
|
||||
|
||||
switch v := val.(type) {
|
||||
case *Scalar:
|
||||
case *model.Scalar:
|
||||
// As the expression type does not change we can safely default to 0
|
||||
// as the fingerprint for scalar expressions.
|
||||
ss := sampleStreams[0]
|
||||
if ss == nil {
|
||||
ss = &SampleStream{Values: make([]model.SamplePair, 0, numSteps)}
|
||||
ss = &sampleStream{Values: make([]model.SamplePair, 0, numSteps)}
|
||||
sampleStreams[0] = ss
|
||||
}
|
||||
ss.Values = append(ss.Values, model.SamplePair{
|
||||
Value: v.Value,
|
||||
Timestamp: v.Timestamp,
|
||||
})
|
||||
case Vector:
|
||||
case vector:
|
||||
for _, sample := range v {
|
||||
fp := sample.Metric.Metric.Fingerprint()
|
||||
ss := sampleStreams[fp]
|
||||
if ss == nil {
|
||||
ss = &SampleStream{
|
||||
ss = &sampleStream{
|
||||
Metric: sample.Metric,
|
||||
Values: make([]model.SamplePair, 0, numSteps),
|
||||
}
|
||||
|
@ -514,9 +477,9 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
|
|||
}
|
||||
|
||||
appendTimer := query.stats.GetTimer(stats.ResultAppendTime).Start()
|
||||
matrix := Matrix{}
|
||||
for _, sampleStream := range sampleStreams {
|
||||
matrix = append(matrix, sampleStream)
|
||||
mat := matrix{}
|
||||
for _, ss := range sampleStreams {
|
||||
mat = append(mat, ss)
|
||||
}
|
||||
appendTimer.Stop()
|
||||
|
||||
|
@ -524,11 +487,14 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Turn matrix type with protected metric into model.Matrix.
|
||||
resMatrix := mat.value()
|
||||
|
||||
sortTimer := query.stats.GetTimer(stats.ResultSortTime).Start()
|
||||
sort.Sort(matrix)
|
||||
sort.Sort(resMatrix)
|
||||
sortTimer.Stop()
|
||||
|
||||
return matrix, nil
|
||||
return resMatrix, nil
|
||||
}
|
||||
|
||||
// An evaluator evaluates given expressions at a fixed timestamp. It is attached to an
|
||||
|
@ -568,9 +534,9 @@ func (ev *evaluator) recover(errp *error) {
|
|||
}
|
||||
|
||||
// evalScalar attempts to evaluate e to a scalar value and errors otherwise.
|
||||
func (ev *evaluator) evalScalar(e Expr) *Scalar {
|
||||
func (ev *evaluator) evalScalar(e Expr) *model.Scalar {
|
||||
val := ev.eval(e)
|
||||
sv, ok := val.(*Scalar)
|
||||
sv, ok := val.(*model.Scalar)
|
||||
if !ok {
|
||||
ev.errorf("expected scalar but got %s", val.Type())
|
||||
}
|
||||
|
@ -578,9 +544,9 @@ func (ev *evaluator) evalScalar(e Expr) *Scalar {
|
|||
}
|
||||
|
||||
// evalVector attempts to evaluate e to a vector value and errors otherwise.
|
||||
func (ev *evaluator) evalVector(e Expr) Vector {
|
||||
func (ev *evaluator) evalVector(e Expr) vector {
|
||||
val := ev.eval(e)
|
||||
vec, ok := val.(Vector)
|
||||
vec, ok := val.(vector)
|
||||
if !ok {
|
||||
ev.errorf("expected vector but got %s", val.Type())
|
||||
}
|
||||
|
@ -600,9 +566,9 @@ func (ev *evaluator) evalFloat(e Expr) float64 {
|
|||
}
|
||||
|
||||
// evalMatrix attempts to evaluate e into a matrix and errors otherwise.
|
||||
func (ev *evaluator) evalMatrix(e Expr) Matrix {
|
||||
func (ev *evaluator) evalMatrix(e Expr) matrix {
|
||||
val := ev.eval(e)
|
||||
mat, ok := val.(Matrix)
|
||||
mat, ok := val.(matrix)
|
||||
if !ok {
|
||||
ev.errorf("expected matrix but got %s", val.Type())
|
||||
}
|
||||
|
@ -610,7 +576,7 @@ func (ev *evaluator) evalMatrix(e Expr) Matrix {
|
|||
}
|
||||
|
||||
// evalMatrixBounds attempts to evaluate e to matrix boundaries and errors otherwise.
|
||||
func (ev *evaluator) evalMatrixBounds(e Expr) Matrix {
|
||||
func (ev *evaluator) evalMatrixBounds(e Expr) matrix {
|
||||
ms, ok := e.(*MatrixSelector)
|
||||
if !ok {
|
||||
ev.errorf("matrix bounds can only be evaluated for matrix selectors, got %T", e)
|
||||
|
@ -619,9 +585,9 @@ func (ev *evaluator) evalMatrixBounds(e Expr) Matrix {
|
|||
}
|
||||
|
||||
// evalString attempts to evaluate e to a string value and errors otherwise.
|
||||
func (ev *evaluator) evalString(e Expr) *String {
|
||||
func (ev *evaluator) evalString(e Expr) *model.String {
|
||||
val := ev.eval(e)
|
||||
sv, ok := val.(*String)
|
||||
sv, ok := val.(*model.String)
|
||||
if !ok {
|
||||
ev.errorf("expected string but got %s", val.Type())
|
||||
}
|
||||
|
@ -629,7 +595,7 @@ func (ev *evaluator) evalString(e Expr) *String {
|
|||
}
|
||||
|
||||
// evalOneOf evaluates e and errors unless the result is of one of the given types.
|
||||
func (ev *evaluator) evalOneOf(e Expr, t1, t2 ExprType) Value {
|
||||
func (ev *evaluator) evalOneOf(e Expr, t1, t2 model.ValueType) model.Value {
|
||||
val := ev.eval(e)
|
||||
if val.Type() != t1 && val.Type() != t2 {
|
||||
ev.errorf("expected %s or %s but got %s", t1, t2, val.Type())
|
||||
|
@ -637,15 +603,15 @@ func (ev *evaluator) evalOneOf(e Expr, t1, t2 ExprType) Value {
|
|||
return val
|
||||
}
|
||||
|
||||
func (ev *evaluator) Eval(expr Expr) (v Value, err error) {
|
||||
func (ev *evaluator) Eval(expr Expr) (v model.Value, err error) {
|
||||
defer ev.recover(&err)
|
||||
return ev.eval(expr), nil
|
||||
}
|
||||
|
||||
// eval evaluates the given expression as the given AST expression node requires.
|
||||
func (ev *evaluator) eval(expr Expr) Value {
|
||||
func (ev *evaluator) eval(expr Expr) model.Value {
|
||||
// This is the top-level evaluation method.
|
||||
// Thus, we check for timeout/cancellation here.
|
||||
// Thus, we check for timeout/cancelation here.
|
||||
if err := contextDone(ev.ctx, "expression evaluation"); err != nil {
|
||||
ev.error(err)
|
||||
}
|
||||
|
@ -656,30 +622,30 @@ func (ev *evaluator) eval(expr Expr) Value {
|
|||
return ev.aggregation(e.Op, e.Grouping, e.KeepExtraLabels, vector)
|
||||
|
||||
case *BinaryExpr:
|
||||
lhs := ev.evalOneOf(e.LHS, ExprScalar, ExprVector)
|
||||
rhs := ev.evalOneOf(e.RHS, ExprScalar, ExprVector)
|
||||
lhs := ev.evalOneOf(e.LHS, model.ValScalar, model.ValVector)
|
||||
rhs := ev.evalOneOf(e.RHS, model.ValScalar, model.ValVector)
|
||||
|
||||
switch lt, rt := lhs.Type(), rhs.Type(); {
|
||||
case lt == ExprScalar && rt == ExprScalar:
|
||||
return &Scalar{
|
||||
Value: scalarBinop(e.Op, lhs.(*Scalar).Value, rhs.(*Scalar).Value),
|
||||
case lt == model.ValScalar && rt == model.ValScalar:
|
||||
return &model.Scalar{
|
||||
Value: scalarBinop(e.Op, lhs.(*model.Scalar).Value, rhs.(*model.Scalar).Value),
|
||||
Timestamp: ev.Timestamp,
|
||||
}
|
||||
|
||||
case lt == ExprVector && rt == ExprVector:
|
||||
case lt == model.ValVector && rt == model.ValVector:
|
||||
switch e.Op {
|
||||
case itemLAND:
|
||||
return ev.vectorAnd(lhs.(Vector), rhs.(Vector), e.VectorMatching)
|
||||
return ev.vectorAnd(lhs.(vector), rhs.(vector), e.VectorMatching)
|
||||
case itemLOR:
|
||||
return ev.vectorOr(lhs.(Vector), rhs.(Vector), e.VectorMatching)
|
||||
return ev.vectorOr(lhs.(vector), rhs.(vector), e.VectorMatching)
|
||||
default:
|
||||
return ev.vectorBinop(e.Op, lhs.(Vector), rhs.(Vector), e.VectorMatching)
|
||||
return ev.vectorBinop(e.Op, lhs.(vector), rhs.(vector), e.VectorMatching)
|
||||
}
|
||||
case lt == ExprVector && rt == ExprScalar:
|
||||
return ev.vectorScalarBinop(e.Op, lhs.(Vector), rhs.(*Scalar), false)
|
||||
case lt == model.ValVector && rt == model.ValScalar:
|
||||
return ev.vectorScalarBinop(e.Op, lhs.(vector), rhs.(*model.Scalar), false)
|
||||
|
||||
case lt == ExprScalar && rt == ExprVector:
|
||||
return ev.vectorScalarBinop(e.Op, rhs.(Vector), lhs.(*Scalar), true)
|
||||
case lt == model.ValScalar && rt == model.ValVector:
|
||||
return ev.vectorScalarBinop(e.Op, rhs.(vector), lhs.(*model.Scalar), true)
|
||||
}
|
||||
|
||||
case *Call:
|
||||
|
@ -689,22 +655,22 @@ func (ev *evaluator) eval(expr Expr) Value {
|
|||
return ev.matrixSelector(e)
|
||||
|
||||
case *NumberLiteral:
|
||||
return &Scalar{Value: e.Val, Timestamp: ev.Timestamp}
|
||||
return &model.Scalar{Value: e.Val, Timestamp: ev.Timestamp}
|
||||
|
||||
case *ParenExpr:
|
||||
return ev.eval(e.Expr)
|
||||
|
||||
case *StringLiteral:
|
||||
return &String{Value: e.Val, Timestamp: ev.Timestamp}
|
||||
return &model.String{Value: e.Val, Timestamp: ev.Timestamp}
|
||||
|
||||
case *UnaryExpr:
|
||||
se := ev.evalOneOf(e.Expr, ExprScalar, ExprVector)
|
||||
se := ev.evalOneOf(e.Expr, model.ValScalar, model.ValVector)
|
||||
// Only + and - are possible operators.
|
||||
if e.Op == itemSUB {
|
||||
switch v := se.(type) {
|
||||
case *Scalar:
|
||||
case *model.Scalar:
|
||||
v.Value = -v.Value
|
||||
case Vector:
|
||||
case vector:
|
||||
for i, sv := range v {
|
||||
v[i].Value = -sv.Value
|
||||
}
|
||||
|
@ -719,13 +685,13 @@ func (ev *evaluator) eval(expr Expr) Value {
|
|||
}
|
||||
|
||||
// vectorSelector evaluates a *VectorSelector expression.
|
||||
func (ev *evaluator) vectorSelector(node *VectorSelector) Vector {
|
||||
vec := Vector{}
|
||||
func (ev *evaluator) vectorSelector(node *VectorSelector) vector {
|
||||
vec := vector{}
|
||||
for fp, it := range node.iterators {
|
||||
sampleCandidates := it.ValueAtTime(ev.Timestamp.Add(-node.Offset))
|
||||
samplePair := chooseClosestSample(sampleCandidates, ev.Timestamp.Add(-node.Offset))
|
||||
if samplePair != nil {
|
||||
vec = append(vec, &Sample{
|
||||
vec = append(vec, &sample{
|
||||
Metric: node.metrics[fp],
|
||||
Value: samplePair.Value,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -736,13 +702,13 @@ func (ev *evaluator) vectorSelector(node *VectorSelector) Vector {
|
|||
}
|
||||
|
||||
// matrixSelector evaluates a *MatrixSelector expression.
|
||||
func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix {
|
||||
func (ev *evaluator) matrixSelector(node *MatrixSelector) matrix {
|
||||
interval := metric.Interval{
|
||||
OldestInclusive: ev.Timestamp.Add(-node.Range - node.Offset),
|
||||
NewestInclusive: ev.Timestamp.Add(-node.Offset),
|
||||
}
|
||||
|
||||
sampleStreams := make([]*SampleStream, 0, len(node.iterators))
|
||||
sampleStreams := make([]*sampleStream, 0, len(node.iterators))
|
||||
for fp, it := range node.iterators {
|
||||
samplePairs := it.RangeValues(interval)
|
||||
if len(samplePairs) == 0 {
|
||||
|
@ -755,46 +721,46 @@ func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix {
|
|||
}
|
||||
}
|
||||
|
||||
sampleStream := &SampleStream{
|
||||
sampleStream := &sampleStream{
|
||||
Metric: node.metrics[fp],
|
||||
Values: samplePairs,
|
||||
}
|
||||
sampleStreams = append(sampleStreams, sampleStream)
|
||||
}
|
||||
return Matrix(sampleStreams)
|
||||
return matrix(sampleStreams)
|
||||
}
|
||||
|
||||
// matrixSelectorBounds evaluates the boundaries of a *MatrixSelector.
|
||||
func (ev *evaluator) matrixSelectorBounds(node *MatrixSelector) Matrix {
|
||||
func (ev *evaluator) matrixSelectorBounds(node *MatrixSelector) matrix {
|
||||
interval := metric.Interval{
|
||||
OldestInclusive: ev.Timestamp.Add(-node.Range - node.Offset),
|
||||
NewestInclusive: ev.Timestamp.Add(-node.Offset),
|
||||
}
|
||||
|
||||
sampleStreams := make([]*SampleStream, 0, len(node.iterators))
|
||||
sampleStreams := make([]*sampleStream, 0, len(node.iterators))
|
||||
for fp, it := range node.iterators {
|
||||
samplePairs := it.BoundaryValues(interval)
|
||||
if len(samplePairs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sampleStream := &SampleStream{
|
||||
ss := &sampleStream{
|
||||
Metric: node.metrics[fp],
|
||||
Values: samplePairs,
|
||||
}
|
||||
sampleStreams = append(sampleStreams, sampleStream)
|
||||
sampleStreams = append(sampleStreams, ss)
|
||||
}
|
||||
return Matrix(sampleStreams)
|
||||
return matrix(sampleStreams)
|
||||
}
|
||||
|
||||
func (ev *evaluator) vectorAnd(lhs, rhs Vector, matching *VectorMatching) Vector {
|
||||
func (ev *evaluator) vectorAnd(lhs, rhs vector, matching *VectorMatching) vector {
|
||||
if matching.Card != CardManyToMany {
|
||||
panic("logical operations must always be many-to-many matching")
|
||||
}
|
||||
// If no matching labels are specified, match by all labels.
|
||||
sigf := signatureFunc(matching.On...)
|
||||
|
||||
var result Vector
|
||||
var result vector
|
||||
// The set of signatures for the right-hand side vector.
|
||||
rightSigs := map[uint64]struct{}{}
|
||||
// Add all rhs samples to a map so we can easily find matches later.
|
||||
|
@ -811,13 +777,13 @@ func (ev *evaluator) vectorAnd(lhs, rhs Vector, matching *VectorMatching) Vector
|
|||
return result
|
||||
}
|
||||
|
||||
func (ev *evaluator) vectorOr(lhs, rhs Vector, matching *VectorMatching) Vector {
|
||||
func (ev *evaluator) vectorOr(lhs, rhs vector, matching *VectorMatching) vector {
|
||||
if matching.Card != CardManyToMany {
|
||||
panic("logical operations must always be many-to-many matching")
|
||||
}
|
||||
sigf := signatureFunc(matching.On...)
|
||||
|
||||
var result Vector
|
||||
var result vector
|
||||
leftSigs := map[uint64]struct{}{}
|
||||
// Add everything from the left-hand-side vector.
|
||||
for _, ls := range lhs {
|
||||
|
@ -834,12 +800,12 @@ func (ev *evaluator) vectorOr(lhs, rhs Vector, matching *VectorMatching) Vector
|
|||
}
|
||||
|
||||
// vectorBinop evaluates a binary operation between two vector, excluding AND and OR.
|
||||
func (ev *evaluator) vectorBinop(op itemType, lhs, rhs Vector, matching *VectorMatching) Vector {
|
||||
func (ev *evaluator) vectorBinop(op itemType, lhs, rhs vector, matching *VectorMatching) vector {
|
||||
if matching.Card == CardManyToMany {
|
||||
panic("many-to-many only allowed for AND and OR")
|
||||
}
|
||||
var (
|
||||
result = Vector{}
|
||||
result = vector{}
|
||||
sigf = signatureFunc(matching.On...)
|
||||
resultLabels = append(matching.On, matching.Include...)
|
||||
)
|
||||
|
@ -852,7 +818,7 @@ func (ev *evaluator) vectorBinop(op itemType, lhs, rhs Vector, matching *VectorM
|
|||
}
|
||||
|
||||
// All samples from the rhs hashed by the matching label/values.
|
||||
rightSigs := map[uint64]*Sample{}
|
||||
rightSigs := map[uint64]*sample{}
|
||||
|
||||
// Add all rhs samples to a map so we can easily find matches later.
|
||||
for _, rs := range rhs {
|
||||
|
@ -911,7 +877,7 @@ func (ev *evaluator) vectorBinop(op itemType, lhs, rhs Vector, matching *VectorM
|
|||
insertedSigs[insertSig] = struct{}{}
|
||||
}
|
||||
|
||||
result = append(result, &Sample{
|
||||
result = append(result, &sample{
|
||||
Metric: metric,
|
||||
Value: value,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -922,21 +888,21 @@ func (ev *evaluator) vectorBinop(op itemType, lhs, rhs Vector, matching *VectorM
|
|||
|
||||
// signatureFunc returns a function that calculates the signature for a metric
|
||||
// based on the provided labels.
|
||||
func signatureFunc(labels ...model.LabelName) func(m model.COWMetric) uint64 {
|
||||
func signatureFunc(labels ...model.LabelName) func(m metric.Metric) uint64 {
|
||||
if len(labels) == 0 {
|
||||
return func(m model.COWMetric) uint64 {
|
||||
return func(m metric.Metric) uint64 {
|
||||
m.Del(model.MetricNameLabel)
|
||||
return uint64(m.Metric.Fingerprint())
|
||||
}
|
||||
}
|
||||
return func(m model.COWMetric) uint64 {
|
||||
return func(m metric.Metric) uint64 {
|
||||
return model.SignatureForLabels(m.Metric, labels...)
|
||||
}
|
||||
}
|
||||
|
||||
// resultMetric returns the metric for the given sample(s) based on the vector
|
||||
// binary operation and the matching options.
|
||||
func resultMetric(met model.COWMetric, op itemType, labels ...model.LabelName) model.COWMetric {
|
||||
func resultMetric(met metric.Metric, op itemType, labels ...model.LabelName) metric.Metric {
|
||||
if len(labels) == 0 {
|
||||
if shouldDropMetricName(op) {
|
||||
met.Del(model.MetricNameLabel)
|
||||
|
@ -951,12 +917,12 @@ func resultMetric(met model.COWMetric, op itemType, labels ...model.LabelName) m
|
|||
m[ln] = v
|
||||
}
|
||||
}
|
||||
return model.COWMetric{Metric: m, Copied: false}
|
||||
return metric.Metric{Metric: m, Copied: false}
|
||||
}
|
||||
|
||||
// vectorScalarBinop evaluates a binary operation between a vector and a scalar.
|
||||
func (ev *evaluator) vectorScalarBinop(op itemType, lhs Vector, rhs *Scalar, swap bool) Vector {
|
||||
vector := make(Vector, 0, len(lhs))
|
||||
func (ev *evaluator) vectorScalarBinop(op itemType, lhs vector, rhs *model.Scalar, swap bool) vector {
|
||||
vec := make(vector, 0, len(lhs))
|
||||
|
||||
for _, lhsSample := range lhs {
|
||||
lv, rv := lhsSample.Value, rhs.Value
|
||||
|
@ -971,10 +937,10 @@ func (ev *evaluator) vectorScalarBinop(op itemType, lhs Vector, rhs *Scalar, swa
|
|||
if shouldDropMetricName(op) {
|
||||
lhsSample.Metric.Del(model.MetricNameLabel)
|
||||
}
|
||||
vector = append(vector, lhsSample)
|
||||
vec = append(vec, lhsSample)
|
||||
}
|
||||
}
|
||||
return vector
|
||||
return vec
|
||||
}
|
||||
|
||||
// scalarBinop evaluates a binary operation between two scalars.
|
||||
|
@ -1042,7 +1008,7 @@ func vectorElemBinop(op itemType, lhs, rhs model.SampleValue) (model.SampleValue
|
|||
}
|
||||
|
||||
// labelIntersection returns the metric of common label/value pairs of two input metrics.
|
||||
func labelIntersection(metric1, metric2 model.COWMetric) model.COWMetric {
|
||||
func labelIntersection(metric1, metric2 metric.Metric) metric.Metric {
|
||||
for label, value := range metric1.Metric {
|
||||
if metric2.Metric[label] != value {
|
||||
metric1.Del(label)
|
||||
|
@ -1052,29 +1018,29 @@ func labelIntersection(metric1, metric2 model.COWMetric) model.COWMetric {
|
|||
}
|
||||
|
||||
type groupedAggregation struct {
|
||||
labels model.COWMetric
|
||||
labels metric.Metric
|
||||
value model.SampleValue
|
||||
valuesSquaredSum model.SampleValue
|
||||
groupCount int
|
||||
}
|
||||
|
||||
// aggregation evaluates an aggregation operation on a vector.
|
||||
func (ev *evaluator) aggregation(op itemType, grouping model.LabelNames, keepExtra bool, vector Vector) Vector {
|
||||
func (ev *evaluator) aggregation(op itemType, grouping model.LabelNames, keepExtra bool, vec vector) vector {
|
||||
|
||||
result := map[uint64]*groupedAggregation{}
|
||||
|
||||
for _, sample := range vector {
|
||||
for _, sample := range vec {
|
||||
groupingKey := model.SignatureForLabels(sample.Metric.Metric, grouping...)
|
||||
|
||||
groupedResult, ok := result[groupingKey]
|
||||
// Add a new group if it doesn't exist.
|
||||
if !ok {
|
||||
var m model.COWMetric
|
||||
var m metric.Metric
|
||||
if keepExtra {
|
||||
m = sample.Metric
|
||||
m.Del(model.MetricNameLabel)
|
||||
} else {
|
||||
m = model.COWMetric{
|
||||
m = metric.Metric{
|
||||
Metric: model.Metric{},
|
||||
Copied: true,
|
||||
}
|
||||
|
@ -1123,7 +1089,7 @@ func (ev *evaluator) aggregation(op itemType, grouping model.LabelNames, keepExt
|
|||
}
|
||||
|
||||
// Construct the result vector from the aggregated groups.
|
||||
resultVector := make(Vector, 0, len(result))
|
||||
resultVector := make(vector, 0, len(result))
|
||||
|
||||
for _, aggr := range result {
|
||||
switch op {
|
||||
|
@ -1140,7 +1106,7 @@ func (ev *evaluator) aggregation(op itemType, grouping model.LabelNames, keepExt
|
|||
default:
|
||||
// For other aggregations, we already have the right value.
|
||||
}
|
||||
sample := &Sample{
|
||||
sample := &sample{
|
||||
Metric: aggr.labels,
|
||||
Value: aggr.value,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
|
|
@ -30,29 +30,29 @@ import (
|
|||
// used by function nodes.
|
||||
type Function struct {
|
||||
Name string
|
||||
ArgTypes []ExprType
|
||||
ArgTypes []model.ValueType
|
||||
OptionalArgs int
|
||||
ReturnType ExprType
|
||||
Call func(ev *evaluator, args Expressions) Value
|
||||
ReturnType model.ValueType
|
||||
Call func(ev *evaluator, args Expressions) model.Value
|
||||
}
|
||||
|
||||
// === time() model.SampleValue ===
|
||||
func funcTime(ev *evaluator, args Expressions) Value {
|
||||
return &Scalar{
|
||||
func funcTime(ev *evaluator, args Expressions) model.Value {
|
||||
return &model.Scalar{
|
||||
Value: model.SampleValue(ev.Timestamp.Unix()),
|
||||
Timestamp: ev.Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// === delta(matrix ExprMatrix, isCounter=0 ExprScalar) Vector ===
|
||||
func funcDelta(ev *evaluator, args Expressions) Value {
|
||||
// === delta(matrix model.ValMatrix, isCounter=0 model.ValScalar) Vector ===
|
||||
func funcDelta(ev *evaluator, args Expressions) model.Value {
|
||||
isCounter := len(args) >= 2 && ev.evalInt(args[1]) > 0
|
||||
resultVector := Vector{}
|
||||
resultVector := vector{}
|
||||
|
||||
// If we treat these metrics as counters, we need to fetch all values
|
||||
// in the interval to find breaks in the timeseries' monotonicity.
|
||||
// I.e. if a counter resets, we want to ignore that reset.
|
||||
var matrixValue Matrix
|
||||
var matrixValue matrix
|
||||
if isCounter {
|
||||
matrixValue = ev.evalMatrix(args[0])
|
||||
} else {
|
||||
|
@ -65,8 +65,10 @@ func funcDelta(ev *evaluator, args Expressions) Value {
|
|||
continue
|
||||
}
|
||||
|
||||
counterCorrection := model.SampleValue(0)
|
||||
lastValue := model.SampleValue(0)
|
||||
var (
|
||||
counterCorrection model.SampleValue
|
||||
lastValue model.SampleValue
|
||||
)
|
||||
for _, sample := range samples.Values {
|
||||
currentValue := sample.Value
|
||||
if isCounter && currentValue < lastValue {
|
||||
|
@ -93,7 +95,7 @@ func funcDelta(ev *evaluator, args Expressions) Value {
|
|||
intervalCorrection := model.SampleValue(targetInterval) / model.SampleValue(sampledInterval)
|
||||
resultValue *= intervalCorrection
|
||||
|
||||
resultSample := &Sample{
|
||||
resultSample := &sample{
|
||||
Metric: samples.Metric,
|
||||
Value: resultValue,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -104,12 +106,12 @@ func funcDelta(ev *evaluator, args Expressions) Value {
|
|||
return resultVector
|
||||
}
|
||||
|
||||
// === rate(node ExprMatrix) Vector ===
|
||||
func funcRate(ev *evaluator, args Expressions) Value {
|
||||
// === rate(node model.ValMatrix) Vector ===
|
||||
func funcRate(ev *evaluator, args Expressions) model.Value {
|
||||
args = append(args, &NumberLiteral{1})
|
||||
vector := funcDelta(ev, args).(Vector)
|
||||
vector := funcDelta(ev, args).(vector)
|
||||
|
||||
// TODO: could be other type of ExprMatrix in the future (right now, only
|
||||
// TODO: could be other type of model.ValMatrix in the future (right now, only
|
||||
// MatrixSelector exists). Find a better way of getting the duration of a
|
||||
// matrix, such as looking at the samples themselves.
|
||||
interval := args[0].(*MatrixSelector).Range
|
||||
|
@ -119,38 +121,38 @@ func funcRate(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === increase(node ExprMatrix) Vector ===
|
||||
func funcIncrease(ev *evaluator, args Expressions) Value {
|
||||
// === increase(node model.ValMatrix) Vector ===
|
||||
func funcIncrease(ev *evaluator, args Expressions) model.Value {
|
||||
args = append(args, &NumberLiteral{1})
|
||||
vector := funcDelta(ev, args).(Vector)
|
||||
return vector
|
||||
return funcDelta(ev, args).(vector)
|
||||
}
|
||||
|
||||
// === sort(node ExprVector) Vector ===
|
||||
func funcSort(ev *evaluator, args Expressions) Value {
|
||||
// === sort(node model.ValVector) Vector ===
|
||||
func funcSort(ev *evaluator, args Expressions) model.Value {
|
||||
byValueSorter := vectorByValueHeap(ev.evalVector(args[0]))
|
||||
sort.Sort(byValueSorter)
|
||||
return Vector(byValueSorter)
|
||||
return vector(byValueSorter)
|
||||
}
|
||||
|
||||
// === sortDesc(node ExprVector) Vector ===
|
||||
func funcSortDesc(ev *evaluator, args Expressions) Value {
|
||||
// === sortDesc(node model.ValVector) Vector ===
|
||||
func funcSortDesc(ev *evaluator, args Expressions) model.Value {
|
||||
byValueSorter := vectorByValueHeap(ev.evalVector(args[0]))
|
||||
sort.Sort(sort.Reverse(byValueSorter))
|
||||
return Vector(byValueSorter)
|
||||
|
||||
return vector(byValueSorter)
|
||||
}
|
||||
|
||||
// === topk(k ExprScalar, node ExprVector) Vector ===
|
||||
func funcTopk(ev *evaluator, args Expressions) Value {
|
||||
// === topk(k model.ValScalar, node model.ValVector) Vector ===
|
||||
func funcTopk(ev *evaluator, args Expressions) model.Value {
|
||||
k := ev.evalInt(args[0])
|
||||
if k < 1 {
|
||||
return Vector{}
|
||||
return vector{}
|
||||
}
|
||||
vector := ev.evalVector(args[1])
|
||||
vec := ev.evalVector(args[1])
|
||||
|
||||
topk := make(vectorByValueHeap, 0, k)
|
||||
|
||||
for _, el := range vector {
|
||||
for _, el := range vec {
|
||||
if len(topk) < k || topk[0].Value < el.Value {
|
||||
if len(topk) == k {
|
||||
heap.Pop(&topk)
|
||||
|
@ -159,21 +161,21 @@ func funcTopk(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
}
|
||||
sort.Sort(sort.Reverse(topk))
|
||||
return Vector(topk)
|
||||
return vector(topk)
|
||||
}
|
||||
|
||||
// === bottomk(k ExprScalar, node ExprVector) Vector ===
|
||||
func funcBottomk(ev *evaluator, args Expressions) Value {
|
||||
// === bottomk(k model.ValScalar, node model.ValVector) Vector ===
|
||||
func funcBottomk(ev *evaluator, args Expressions) model.Value {
|
||||
k := ev.evalInt(args[0])
|
||||
if k < 1 {
|
||||
return Vector{}
|
||||
return vector{}
|
||||
}
|
||||
vector := ev.evalVector(args[1])
|
||||
vec := ev.evalVector(args[1])
|
||||
|
||||
bottomk := make(vectorByValueHeap, 0, k)
|
||||
bkHeap := reverseHeap{Interface: &bottomk}
|
||||
|
||||
for _, el := range vector {
|
||||
for _, el := range vec {
|
||||
if len(bottomk) < k || bottomk[0].Value > el.Value {
|
||||
if len(bottomk) == k {
|
||||
heap.Pop(&bkHeap)
|
||||
|
@ -182,17 +184,17 @@ func funcBottomk(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
}
|
||||
sort.Sort(bottomk)
|
||||
return Vector(bottomk)
|
||||
return vector(bottomk)
|
||||
}
|
||||
|
||||
// === drop_common_labels(node ExprVector) Vector ===
|
||||
func funcDropCommonLabels(ev *evaluator, args Expressions) Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
if len(vector) < 1 {
|
||||
return Vector{}
|
||||
// === drop_common_labels(node model.ValVector) Vector ===
|
||||
func funcDropCommonLabels(ev *evaluator, args Expressions) model.Value {
|
||||
vec := ev.evalVector(args[0])
|
||||
if len(vec) < 1 {
|
||||
return vector{}
|
||||
}
|
||||
common := model.LabelSet{}
|
||||
for k, v := range vector[0].Metric.Metric {
|
||||
for k, v := range vec[0].Metric.Metric {
|
||||
// TODO(julius): Should we also drop common metric names?
|
||||
if k == model.MetricNameLabel {
|
||||
continue
|
||||
|
@ -200,7 +202,7 @@ func funcDropCommonLabels(ev *evaluator, args Expressions) Value {
|
|||
common[k] = v
|
||||
}
|
||||
|
||||
for _, el := range vector[1:] {
|
||||
for _, el := range vec[1:] {
|
||||
for k, v := range common {
|
||||
if el.Metric.Metric[k] != v {
|
||||
// Deletion of map entries while iterating over them is safe.
|
||||
|
@ -212,18 +214,18 @@ func funcDropCommonLabels(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
}
|
||||
|
||||
for _, el := range vector {
|
||||
for _, el := range vec {
|
||||
for k := range el.Metric.Metric {
|
||||
if _, ok := common[k]; ok {
|
||||
el.Metric.Del(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector
|
||||
return vec
|
||||
}
|
||||
|
||||
// === round(vector ExprVector, toNearest=1 Scalar) Vector ===
|
||||
func funcRound(ev *evaluator, args Expressions) Value {
|
||||
// === round(vector model.ValVector, toNearest=1 Scalar) Vector ===
|
||||
func funcRound(ev *evaluator, args Expressions) model.Value {
|
||||
// round returns a number rounded to toNearest.
|
||||
// Ties are solved by rounding up.
|
||||
toNearest := float64(1)
|
||||
|
@ -233,42 +235,42 @@ func funcRound(ev *evaluator, args Expressions) Value {
|
|||
// Invert as it seems to cause fewer floating point accuracy issues.
|
||||
toNearestInverse := 1.0 / toNearest
|
||||
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
vec := ev.evalVector(args[0])
|
||||
for _, el := range vec {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
el.Value = model.SampleValue(math.Floor(float64(el.Value)*toNearestInverse+0.5) / toNearestInverse)
|
||||
}
|
||||
return vector
|
||||
return vec
|
||||
}
|
||||
|
||||
// === scalar(node ExprVector) Scalar ===
|
||||
func funcScalar(ev *evaluator, args Expressions) Value {
|
||||
// === scalar(node model.ValVector) Scalar ===
|
||||
func funcScalar(ev *evaluator, args Expressions) model.Value {
|
||||
v := ev.evalVector(args[0])
|
||||
if len(v) != 1 {
|
||||
return &Scalar{model.SampleValue(math.NaN()), ev.Timestamp}
|
||||
return &model.Scalar{model.SampleValue(math.NaN()), ev.Timestamp}
|
||||
}
|
||||
return &Scalar{model.SampleValue(v[0].Value), ev.Timestamp}
|
||||
return &model.Scalar{model.SampleValue(v[0].Value), ev.Timestamp}
|
||||
}
|
||||
|
||||
// === count_scalar(vector ExprVector) model.SampleValue ===
|
||||
func funcCountScalar(ev *evaluator, args Expressions) Value {
|
||||
return &Scalar{
|
||||
// === count_scalar(vector model.ValVector) model.SampleValue ===
|
||||
func funcCountScalar(ev *evaluator, args Expressions) model.Value {
|
||||
return &model.Scalar{
|
||||
Value: model.SampleValue(len(ev.evalVector(args[0]))),
|
||||
Timestamp: ev.Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
func aggrOverTime(ev *evaluator, args Expressions, aggrFn func([]model.SamplePair) model.SampleValue) Value {
|
||||
matrix := ev.evalMatrix(args[0])
|
||||
resultVector := Vector{}
|
||||
func aggrOverTime(ev *evaluator, args Expressions, aggrFn func([]model.SamplePair) model.SampleValue) model.Value {
|
||||
mat := ev.evalMatrix(args[0])
|
||||
resultVector := vector{}
|
||||
|
||||
for _, el := range matrix {
|
||||
for _, el := range mat {
|
||||
if len(el.Values) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
resultVector = append(resultVector, &Sample{
|
||||
resultVector = append(resultVector, &sample{
|
||||
Metric: el.Metric,
|
||||
Value: aggrFn(el.Values),
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -277,8 +279,8 @@ func aggrOverTime(ev *evaluator, args Expressions, aggrFn func([]model.SamplePai
|
|||
return resultVector
|
||||
}
|
||||
|
||||
// === avg_over_time(matrix ExprMatrix) Vector ===
|
||||
func funcAvgOverTime(ev *evaluator, args Expressions) Value {
|
||||
// === avg_over_time(matrix model.ValMatrix) Vector ===
|
||||
func funcAvgOverTime(ev *evaluator, args Expressions) model.Value {
|
||||
return aggrOverTime(ev, args, func(values []model.SamplePair) model.SampleValue {
|
||||
var sum model.SampleValue
|
||||
for _, v := range values {
|
||||
|
@ -288,15 +290,15 @@ func funcAvgOverTime(ev *evaluator, args Expressions) Value {
|
|||
})
|
||||
}
|
||||
|
||||
// === count_over_time(matrix ExprMatrix) Vector ===
|
||||
func funcCountOverTime(ev *evaluator, args Expressions) Value {
|
||||
// === count_over_time(matrix model.ValMatrix) Vector ===
|
||||
func funcCountOverTime(ev *evaluator, args Expressions) model.Value {
|
||||
return aggrOverTime(ev, args, func(values []model.SamplePair) model.SampleValue {
|
||||
return model.SampleValue(len(values))
|
||||
})
|
||||
}
|
||||
|
||||
// === floor(vector ExprVector) Vector ===
|
||||
func funcFloor(ev *evaluator, args Expressions) Value {
|
||||
// === floor(vector model.ValVector) Vector ===
|
||||
func funcFloor(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -305,8 +307,8 @@ func funcFloor(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === max_over_time(matrix ExprMatrix) Vector ===
|
||||
func funcMaxOverTime(ev *evaluator, args Expressions) Value {
|
||||
// === max_over_time(matrix model.ValMatrix) Vector ===
|
||||
func funcMaxOverTime(ev *evaluator, args Expressions) model.Value {
|
||||
return aggrOverTime(ev, args, func(values []model.SamplePair) model.SampleValue {
|
||||
max := math.Inf(-1)
|
||||
for _, v := range values {
|
||||
|
@ -316,8 +318,8 @@ func funcMaxOverTime(ev *evaluator, args Expressions) Value {
|
|||
})
|
||||
}
|
||||
|
||||
// === min_over_time(matrix ExprMatrix) Vector ===
|
||||
func funcMinOverTime(ev *evaluator, args Expressions) Value {
|
||||
// === min_over_time(matrix model.ValMatrix) Vector ===
|
||||
func funcMinOverTime(ev *evaluator, args Expressions) model.Value {
|
||||
return aggrOverTime(ev, args, func(values []model.SamplePair) model.SampleValue {
|
||||
min := math.Inf(1)
|
||||
for _, v := range values {
|
||||
|
@ -327,8 +329,8 @@ func funcMinOverTime(ev *evaluator, args Expressions) Value {
|
|||
})
|
||||
}
|
||||
|
||||
// === sum_over_time(matrix ExprMatrix) Vector ===
|
||||
func funcSumOverTime(ev *evaluator, args Expressions) Value {
|
||||
// === sum_over_time(matrix model.ValMatrix) Vector ===
|
||||
func funcSumOverTime(ev *evaluator, args Expressions) model.Value {
|
||||
return aggrOverTime(ev, args, func(values []model.SamplePair) model.SampleValue {
|
||||
var sum model.SampleValue
|
||||
for _, v := range values {
|
||||
|
@ -338,8 +340,8 @@ func funcSumOverTime(ev *evaluator, args Expressions) Value {
|
|||
})
|
||||
}
|
||||
|
||||
// === abs(vector ExprVector) Vector ===
|
||||
func funcAbs(ev *evaluator, args Expressions) Value {
|
||||
// === abs(vector model.ValVector) Vector ===
|
||||
func funcAbs(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -348,10 +350,10 @@ func funcAbs(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === absent(vector ExprVector) Vector ===
|
||||
func funcAbsent(ev *evaluator, args Expressions) Value {
|
||||
// === absent(vector model.ValVector) Vector ===
|
||||
func funcAbsent(ev *evaluator, args Expressions) model.Value {
|
||||
if len(ev.evalVector(args[0])) > 0 {
|
||||
return Vector{}
|
||||
return vector{}
|
||||
}
|
||||
m := model.Metric{}
|
||||
if vs, ok := args[0].(*VectorSelector); ok {
|
||||
|
@ -361,9 +363,9 @@ func funcAbsent(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
}
|
||||
}
|
||||
return Vector{
|
||||
&Sample{
|
||||
Metric: model.COWMetric{
|
||||
return vector{
|
||||
&sample{
|
||||
Metric: metric.Metric{
|
||||
Metric: m,
|
||||
Copied: true,
|
||||
},
|
||||
|
@ -373,8 +375,8 @@ func funcAbsent(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
}
|
||||
|
||||
// === ceil(vector ExprVector) Vector ===
|
||||
func funcCeil(ev *evaluator, args Expressions) Value {
|
||||
// === ceil(vector model.ValVector) Vector ===
|
||||
func funcCeil(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -383,8 +385,8 @@ func funcCeil(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === exp(vector ExprVector) Vector ===
|
||||
func funcExp(ev *evaluator, args Expressions) Value {
|
||||
// === exp(vector model.ValVector) Vector ===
|
||||
func funcExp(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -394,7 +396,7 @@ func funcExp(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
|
||||
// === sqrt(vector VectorNode) Vector ===
|
||||
func funcSqrt(ev *evaluator, args Expressions) Value {
|
||||
func funcSqrt(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -403,8 +405,8 @@ func funcSqrt(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === ln(vector ExprVector) Vector ===
|
||||
func funcLn(ev *evaluator, args Expressions) Value {
|
||||
// === ln(vector model.ValVector) Vector ===
|
||||
func funcLn(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -413,8 +415,8 @@ func funcLn(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === log2(vector ExprVector) Vector ===
|
||||
func funcLog2(ev *evaluator, args Expressions) Value {
|
||||
// === log2(vector model.ValVector) Vector ===
|
||||
func funcLog2(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -423,8 +425,8 @@ func funcLog2(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === log10(vector ExprVector) Vector ===
|
||||
func funcLog10(ev *evaluator, args Expressions) Value {
|
||||
// === log10(vector model.ValVector) Vector ===
|
||||
func funcLog10(ev *evaluator, args Expressions) model.Value {
|
||||
vector := ev.evalVector(args[0])
|
||||
for _, el := range vector {
|
||||
el.Metric.Del(model.MetricNameLabel)
|
||||
|
@ -433,12 +435,12 @@ func funcLog10(ev *evaluator, args Expressions) Value {
|
|||
return vector
|
||||
}
|
||||
|
||||
// === deriv(node ExprMatrix) Vector ===
|
||||
func funcDeriv(ev *evaluator, args Expressions) Value {
|
||||
resultVector := Vector{}
|
||||
matrix := ev.evalMatrix(args[0])
|
||||
// === deriv(node model.ValMatrix) Vector ===
|
||||
func funcDeriv(ev *evaluator, args Expressions) model.Value {
|
||||
resultVector := vector{}
|
||||
mat := ev.evalMatrix(args[0])
|
||||
|
||||
for _, samples := range matrix {
|
||||
for _, samples := range mat {
|
||||
// No sense in trying to compute a derivative without at least two points.
|
||||
// Drop this vector element.
|
||||
if len(samples.Values) < 2 {
|
||||
|
@ -464,7 +466,7 @@ func funcDeriv(ev *evaluator, args Expressions) Value {
|
|||
|
||||
resultValue := numerator / denominator
|
||||
|
||||
resultSample := &Sample{
|
||||
resultSample := &sample{
|
||||
Metric: samples.Metric,
|
||||
Value: resultValue,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -475,9 +477,9 @@ func funcDeriv(ev *evaluator, args Expressions) Value {
|
|||
return resultVector
|
||||
}
|
||||
|
||||
// === predict_linear(node ExprMatrix, k ExprScalar) Vector ===
|
||||
func funcPredictLinear(ev *evaluator, args Expressions) Value {
|
||||
vector := funcDeriv(ev, args[0:1]).(Vector)
|
||||
// === predict_linear(node model.ValMatrix, k model.ValScalar) Vector ===
|
||||
func funcPredictLinear(ev *evaluator, args Expressions) model.Value {
|
||||
vec := funcDeriv(ev, args[0:1]).(vector)
|
||||
duration := model.SampleValue(model.SampleValue(ev.evalFloat(args[1])))
|
||||
|
||||
excludedLabels := map[model.LabelName]struct{}{
|
||||
|
@ -486,14 +488,14 @@ func funcPredictLinear(ev *evaluator, args Expressions) Value {
|
|||
|
||||
// Calculate predicted delta over the duration.
|
||||
signatureToDelta := map[uint64]model.SampleValue{}
|
||||
for _, el := range vector {
|
||||
for _, el := range vec {
|
||||
signature := model.SignatureWithoutLabels(el.Metric.Metric, excludedLabels)
|
||||
signatureToDelta[signature] = el.Value * duration
|
||||
}
|
||||
|
||||
// add predicted delta to last value.
|
||||
matrixBounds := ev.evalMatrixBounds(args[0])
|
||||
outVec := make(Vector, 0, len(signatureToDelta))
|
||||
outVec := make(vector, 0, len(signatureToDelta))
|
||||
for _, samples := range matrixBounds {
|
||||
if len(samples.Values) < 2 {
|
||||
continue
|
||||
|
@ -502,7 +504,7 @@ func funcPredictLinear(ev *evaluator, args Expressions) Value {
|
|||
delta, ok := signatureToDelta[signature]
|
||||
if ok {
|
||||
samples.Metric.Del(model.MetricNameLabel)
|
||||
outVec = append(outVec, &Sample{
|
||||
outVec = append(outVec, &sample{
|
||||
Metric: samples.Metric,
|
||||
Value: delta + samples.Values[1].Value,
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -512,12 +514,12 @@ func funcPredictLinear(ev *evaluator, args Expressions) Value {
|
|||
return outVec
|
||||
}
|
||||
|
||||
// === histogram_quantile(k ExprScalar, vector ExprVector) Vector ===
|
||||
func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
|
||||
// === histogram_quantile(k model.ValScalar, vector model.ValVector) Vector ===
|
||||
func funcHistogramQuantile(ev *evaluator, args Expressions) model.Value {
|
||||
q := model.SampleValue(ev.evalFloat(args[0]))
|
||||
inVec := ev.evalVector(args[1])
|
||||
|
||||
outVec := Vector{}
|
||||
outVec := vector{}
|
||||
signatureToMetricWithBuckets := map[uint64]*metricWithBuckets{}
|
||||
for _, el := range inVec {
|
||||
upperBound, err := strconv.ParseFloat(
|
||||
|
@ -540,7 +542,7 @@ func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
|
|||
}
|
||||
|
||||
for _, mb := range signatureToMetricWithBuckets {
|
||||
outVec = append(outVec, &Sample{
|
||||
outVec = append(outVec, &sample{
|
||||
Metric: mb.metric,
|
||||
Value: model.SampleValue(quantile(q, mb.buckets)),
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -550,10 +552,10 @@ func funcHistogramQuantile(ev *evaluator, args Expressions) Value {
|
|||
return outVec
|
||||
}
|
||||
|
||||
// === resets(matrix ExprMatrix) Vector ===
|
||||
func funcResets(ev *evaluator, args Expressions) Value {
|
||||
// === resets(matrix model.ValMatrix) Vector ===
|
||||
func funcResets(ev *evaluator, args Expressions) model.Value {
|
||||
in := ev.evalMatrix(args[0])
|
||||
out := make(Vector, 0, len(in))
|
||||
out := make(vector, 0, len(in))
|
||||
|
||||
for _, samples := range in {
|
||||
resets := 0
|
||||
|
@ -566,7 +568,7 @@ func funcResets(ev *evaluator, args Expressions) Value {
|
|||
prev = current
|
||||
}
|
||||
|
||||
rs := &Sample{
|
||||
rs := &sample{
|
||||
Metric: samples.Metric,
|
||||
Value: model.SampleValue(resets),
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -577,10 +579,10 @@ func funcResets(ev *evaluator, args Expressions) Value {
|
|||
return out
|
||||
}
|
||||
|
||||
// === changes(matrix ExprMatrix) Vector ===
|
||||
func funcChanges(ev *evaluator, args Expressions) Value {
|
||||
// === changes(matrix model.ValMatrix) Vector ===
|
||||
func funcChanges(ev *evaluator, args Expressions) model.Value {
|
||||
in := ev.evalMatrix(args[0])
|
||||
out := make(Vector, 0, len(in))
|
||||
out := make(vector, 0, len(in))
|
||||
|
||||
for _, samples := range in {
|
||||
changes := 0
|
||||
|
@ -593,7 +595,7 @@ func funcChanges(ev *evaluator, args Expressions) Value {
|
|||
prev = current
|
||||
}
|
||||
|
||||
rs := &Sample{
|
||||
rs := &sample{
|
||||
Metric: samples.Metric,
|
||||
Value: model.SampleValue(changes),
|
||||
Timestamp: ev.Timestamp,
|
||||
|
@ -604,8 +606,8 @@ func funcChanges(ev *evaluator, args Expressions) Value {
|
|||
return out
|
||||
}
|
||||
|
||||
// === label_replace(vector ExprVector, dst_label, replacement, src_labelname, regex ExprString) Vector ===
|
||||
func funcLabelReplace(ev *evaluator, args Expressions) Value {
|
||||
// === label_replace(vector model.ValVector, dst_label, replacement, src_labelname, regex model.ValString) Vector ===
|
||||
func funcLabelReplace(ev *evaluator, args Expressions) model.Value {
|
||||
var (
|
||||
vector = ev.evalVector(args[0])
|
||||
dst = model.LabelName(ev.evalString(args[1]).Value)
|
||||
|
@ -651,196 +653,196 @@ func funcLabelReplace(ev *evaluator, args Expressions) Value {
|
|||
var functions = map[string]*Function{
|
||||
"abs": {
|
||||
Name: "abs",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcAbs,
|
||||
},
|
||||
"absent": {
|
||||
Name: "absent",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcAbsent,
|
||||
},
|
||||
"increase": {
|
||||
Name: "increase",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcIncrease,
|
||||
},
|
||||
"avg_over_time": {
|
||||
Name: "avg_over_time",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcAvgOverTime,
|
||||
},
|
||||
"bottomk": {
|
||||
Name: "bottomk",
|
||||
ArgTypes: []ExprType{ExprScalar, ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValScalar, model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcBottomk,
|
||||
},
|
||||
"ceil": {
|
||||
Name: "ceil",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcCeil,
|
||||
},
|
||||
"changes": {
|
||||
Name: "changes",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcChanges,
|
||||
},
|
||||
"count_over_time": {
|
||||
Name: "count_over_time",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcCountOverTime,
|
||||
},
|
||||
"count_scalar": {
|
||||
Name: "count_scalar",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprScalar,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValScalar,
|
||||
Call: funcCountScalar,
|
||||
},
|
||||
"delta": {
|
||||
Name: "delta",
|
||||
ArgTypes: []ExprType{ExprMatrix, ExprScalar},
|
||||
ArgTypes: []model.ValueType{model.ValMatrix, model.ValScalar},
|
||||
OptionalArgs: 1, // The 2nd argument is deprecated.
|
||||
ReturnType: ExprVector,
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcDelta,
|
||||
},
|
||||
"deriv": {
|
||||
Name: "deriv",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcDeriv,
|
||||
},
|
||||
"drop_common_labels": {
|
||||
Name: "drop_common_labels",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcDropCommonLabels,
|
||||
},
|
||||
"exp": {
|
||||
Name: "exp",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcExp,
|
||||
},
|
||||
"floor": {
|
||||
Name: "floor",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcFloor,
|
||||
},
|
||||
"histogram_quantile": {
|
||||
Name: "histogram_quantile",
|
||||
ArgTypes: []ExprType{ExprScalar, ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValScalar, model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcHistogramQuantile,
|
||||
},
|
||||
"label_replace": {
|
||||
Name: "label_replace",
|
||||
ArgTypes: []ExprType{ExprVector, ExprString, ExprString, ExprString, ExprString},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector, model.ValString, model.ValString, model.ValString, model.ValString},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcLabelReplace,
|
||||
},
|
||||
"ln": {
|
||||
Name: "ln",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcLn,
|
||||
},
|
||||
"log10": {
|
||||
Name: "log10",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcLog10,
|
||||
},
|
||||
"log2": {
|
||||
Name: "log2",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcLog2,
|
||||
},
|
||||
"max_over_time": {
|
||||
Name: "max_over_time",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcMaxOverTime,
|
||||
},
|
||||
"min_over_time": {
|
||||
Name: "min_over_time",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcMinOverTime,
|
||||
},
|
||||
"predict_linear": {
|
||||
Name: "predict_linear",
|
||||
ArgTypes: []ExprType{ExprMatrix, ExprScalar},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix, model.ValScalar},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcPredictLinear,
|
||||
},
|
||||
"rate": {
|
||||
Name: "rate",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcRate,
|
||||
},
|
||||
"resets": {
|
||||
Name: "resets",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcResets,
|
||||
},
|
||||
"round": {
|
||||
Name: "round",
|
||||
ArgTypes: []ExprType{ExprVector, ExprScalar},
|
||||
ArgTypes: []model.ValueType{model.ValVector, model.ValScalar},
|
||||
OptionalArgs: 1,
|
||||
ReturnType: ExprVector,
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcRound,
|
||||
},
|
||||
"scalar": {
|
||||
Name: "scalar",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprScalar,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValScalar,
|
||||
Call: funcScalar,
|
||||
},
|
||||
"sort": {
|
||||
Name: "sort",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcSort,
|
||||
},
|
||||
"sort_desc": {
|
||||
Name: "sort_desc",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcSortDesc,
|
||||
},
|
||||
"sqrt": {
|
||||
Name: "sqrt",
|
||||
ArgTypes: []ExprType{ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcSqrt,
|
||||
},
|
||||
"sum_over_time": {
|
||||
Name: "sum_over_time",
|
||||
ArgTypes: []ExprType{ExprMatrix},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValMatrix},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcSumOverTime,
|
||||
},
|
||||
"time": {
|
||||
Name: "time",
|
||||
ArgTypes: []ExprType{},
|
||||
ReturnType: ExprScalar,
|
||||
ArgTypes: []model.ValueType{},
|
||||
ReturnType: model.ValScalar,
|
||||
Call: funcTime,
|
||||
},
|
||||
"topk": {
|
||||
Name: "topk",
|
||||
ArgTypes: []ExprType{ExprScalar, ExprVector},
|
||||
ReturnType: ExprVector,
|
||||
ArgTypes: []model.ValueType{model.ValScalar, model.ValVector},
|
||||
ReturnType: model.ValVector,
|
||||
Call: funcTopk,
|
||||
},
|
||||
}
|
||||
|
@ -851,7 +853,7 @@ func getFunction(name string) (*Function, bool) {
|
|||
return function, ok
|
||||
}
|
||||
|
||||
type vectorByValueHeap Vector
|
||||
type vectorByValueHeap vector
|
||||
|
||||
func (s vectorByValueHeap) Len() int {
|
||||
return len(s)
|
||||
|
@ -869,7 +871,7 @@ func (s vectorByValueHeap) Swap(i, j int) {
|
|||
}
|
||||
|
||||
func (s *vectorByValueHeap) Push(x interface{}) {
|
||||
*s = append(*s, x.(*Sample))
|
||||
*s = append(*s, x.(*sample))
|
||||
}
|
||||
|
||||
func (s *vectorByValueHeap) Pop() interface{} {
|
||||
|
|
|
@ -967,7 +967,7 @@ func (p *parser) vectorSelector(name string) *VectorSelector {
|
|||
|
||||
// expectType checks the type of the node and raises an error if it
|
||||
// is not of the expected type.
|
||||
func (p *parser) expectType(node Node, want ExprType, context string) {
|
||||
func (p *parser) expectType(node Node, want model.ValueType, context string) {
|
||||
t := p.checkType(node)
|
||||
if t != want {
|
||||
p.errorf("expected type %s in %s, got %s", want, context, t)
|
||||
|
@ -979,12 +979,12 @@ func (p *parser) expectType(node Node, want ExprType, context string) {
|
|||
//
|
||||
// Some of these checks are redundant as the the parsing stage does not allow
|
||||
// them, but the costs are small and might reveal errors when making changes.
|
||||
func (p *parser) checkType(node Node) (typ ExprType) {
|
||||
func (p *parser) checkType(node Node) (typ model.ValueType) {
|
||||
// For expressions the type is determined by their Type function.
|
||||
// Statements and lists do not have a type but are not invalid either.
|
||||
switch n := node.(type) {
|
||||
case Statements, Expressions, Statement:
|
||||
typ = ExprNone
|
||||
typ = model.ValNone
|
||||
case Expr:
|
||||
typ = n.Type()
|
||||
default:
|
||||
|
@ -996,27 +996,27 @@ func (p *parser) checkType(node Node) (typ ExprType) {
|
|||
switch n := node.(type) {
|
||||
case Statements:
|
||||
for _, s := range n {
|
||||
p.expectType(s, ExprNone, "statement list")
|
||||
p.expectType(s, model.ValNone, "statement list")
|
||||
}
|
||||
case *AlertStmt:
|
||||
p.expectType(n.Expr, ExprVector, "alert statement")
|
||||
p.expectType(n.Expr, model.ValVector, "alert statement")
|
||||
|
||||
case *EvalStmt:
|
||||
ty := p.checkType(n.Expr)
|
||||
if ty == ExprNone {
|
||||
if ty == model.ValNone {
|
||||
p.errorf("evaluation statement must have a valid expression type but got %s", ty)
|
||||
}
|
||||
|
||||
case *RecordStmt:
|
||||
ty := p.checkType(n.Expr)
|
||||
if ty != ExprVector && ty != ExprScalar {
|
||||
if ty != model.ValVector && ty != model.ValScalar {
|
||||
p.errorf("record statement must have a valid expression of type vector or scalar but got %s", ty)
|
||||
}
|
||||
|
||||
case Expressions:
|
||||
for _, e := range n {
|
||||
ty := p.checkType(e)
|
||||
if ty == ExprNone {
|
||||
if ty == model.ValNone {
|
||||
p.errorf("expression must have a valid expression type but got %s", ty)
|
||||
}
|
||||
}
|
||||
|
@ -1024,7 +1024,7 @@ func (p *parser) checkType(node Node) (typ ExprType) {
|
|||
if !n.Op.isAggregator() {
|
||||
p.errorf("aggregation operator expected in aggregation expression but got %q", n.Op)
|
||||
}
|
||||
p.expectType(n.Expr, ExprVector, "aggregation expression")
|
||||
p.expectType(n.Expr, model.ValVector, "aggregation expression")
|
||||
|
||||
case *BinaryExpr:
|
||||
lt := p.checkType(n.LHS)
|
||||
|
@ -1033,11 +1033,11 @@ func (p *parser) checkType(node Node) (typ ExprType) {
|
|||
if !n.Op.isOperator() {
|
||||
p.errorf("only logical and arithmetic operators allowed in binary expression, got %q", n.Op)
|
||||
}
|
||||
if (lt != ExprScalar && lt != ExprVector) || (rt != ExprScalar && rt != ExprVector) {
|
||||
if (lt != model.ValScalar && lt != model.ValVector) || (rt != model.ValScalar && rt != model.ValVector) {
|
||||
p.errorf("binary expression must contain only scalar and vector types")
|
||||
}
|
||||
|
||||
if (lt != ExprVector || rt != ExprVector) && n.VectorMatching != nil {
|
||||
if (lt != model.ValVector || rt != model.ValVector) && n.VectorMatching != nil {
|
||||
if len(n.VectorMatching.On) > 0 {
|
||||
p.errorf("vector matching only allowed between vectors")
|
||||
}
|
||||
|
@ -1054,7 +1054,7 @@ func (p *parser) checkType(node Node) (typ ExprType) {
|
|||
}
|
||||
}
|
||||
|
||||
if (lt == ExprScalar || rt == ExprScalar) && (n.Op == itemLAND || n.Op == itemLOR) {
|
||||
if (lt == model.ValScalar || rt == model.ValScalar) && (n.Op == itemLAND || n.Op == itemLOR) {
|
||||
p.errorf("AND and OR not allowed in binary scalar expression")
|
||||
}
|
||||
|
||||
|
@ -1077,7 +1077,7 @@ func (p *parser) checkType(node Node) (typ ExprType) {
|
|||
if n.Op != itemADD && n.Op != itemSUB {
|
||||
p.errorf("only + and - operators allowed for unary expressions")
|
||||
}
|
||||
if t := p.checkType(n.Expr); t != ExprScalar && t != ExprVector {
|
||||
if t := p.checkType(n.Expr); t != model.ValScalar && t != model.ValVector {
|
||||
p.errorf("unary expression only allowed on expressions of type scalar or vector, got %q", t)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,47 +24,6 @@ import (
|
|||
"github.com/prometheus/prometheus/util/strutil"
|
||||
)
|
||||
|
||||
func (matrix Matrix) String() string {
|
||||
metricStrings := make([]string, 0, len(matrix))
|
||||
for _, sampleStream := range matrix {
|
||||
metricName, hasName := sampleStream.Metric.Metric[model.MetricNameLabel]
|
||||
numLabels := len(sampleStream.Metric.Metric)
|
||||
if hasName {
|
||||
numLabels--
|
||||
}
|
||||
labelStrings := make([]string, 0, numLabels)
|
||||
for label, value := range sampleStream.Metric.Metric {
|
||||
if label != model.MetricNameLabel {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value))
|
||||
}
|
||||
}
|
||||
sort.Strings(labelStrings)
|
||||
valueStrings := make([]string, 0, len(sampleStream.Values))
|
||||
for _, value := range sampleStream.Values {
|
||||
valueStrings = append(valueStrings,
|
||||
fmt.Sprintf("\n%v @[%v]", value.Value, value.Timestamp))
|
||||
}
|
||||
metricStrings = append(metricStrings,
|
||||
fmt.Sprintf("%s{%s} => %s",
|
||||
metricName,
|
||||
strings.Join(labelStrings, ", "),
|
||||
strings.Join(valueStrings, ", ")))
|
||||
}
|
||||
sort.Strings(metricStrings)
|
||||
return strings.Join(metricStrings, "\n")
|
||||
}
|
||||
|
||||
func (vector Vector) String() string {
|
||||
metricStrings := make([]string, 0, len(vector))
|
||||
for _, sample := range vector {
|
||||
metricStrings = append(metricStrings,
|
||||
fmt.Sprintf("%s => %v @[%v]",
|
||||
sample.Metric,
|
||||
sample.Value, sample.Timestamp))
|
||||
}
|
||||
return strings.Join(metricStrings, "\n")
|
||||
}
|
||||
|
||||
// Tree returns a string of the tree structure of the given node.
|
||||
func Tree(node Node) string {
|
||||
return tree(node, "")
|
||||
|
|
|
@ -18,6 +18,8 @@ import (
|
|||
"sort"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/storage/metric"
|
||||
)
|
||||
|
||||
// Helpers to calculate quantiles.
|
||||
|
@ -42,7 +44,7 @@ func (b buckets) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
|||
func (b buckets) Less(i, j int) bool { return b[i].upperBound < b[j].upperBound }
|
||||
|
||||
type metricWithBuckets struct {
|
||||
metric model.COWMetric
|
||||
metric metric.Metric
|
||||
buckets buckets
|
||||
}
|
||||
|
||||
|
|
|
@ -340,25 +340,25 @@ func (ev *evalCmd) expect(pos int, m model.Metric, vals ...sequenceValue) {
|
|||
}
|
||||
|
||||
// compareResult compares the result value with the defined expectation.
|
||||
func (ev *evalCmd) compareResult(result Value) error {
|
||||
func (ev *evalCmd) compareResult(result model.Value) error {
|
||||
switch val := result.(type) {
|
||||
case Matrix:
|
||||
case model.Matrix:
|
||||
if ev.instant {
|
||||
return fmt.Errorf("received range result on instant evaluation")
|
||||
}
|
||||
seen := map[model.Fingerprint]bool{}
|
||||
for pos, v := range val {
|
||||
fp := v.Metric.Metric.Fingerprint()
|
||||
fp := v.Metric.Fingerprint()
|
||||
if _, ok := ev.metrics[fp]; !ok {
|
||||
return fmt.Errorf("unexpected metric %s in result", v.Metric.Metric)
|
||||
return fmt.Errorf("unexpected metric %s in result", v.Metric)
|
||||
}
|
||||
exp := ev.expected[fp]
|
||||
if ev.ordered && exp.pos != pos+1 {
|
||||
return fmt.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric.Metric, exp.vals, exp.pos, pos+1)
|
||||
return fmt.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric, exp.vals, exp.pos, pos+1)
|
||||
}
|
||||
for i, expVal := range exp.vals {
|
||||
if !almostEqual(float64(expVal.value), float64(v.Values[i].Value)) {
|
||||
return fmt.Errorf("expected %v for %s but got %v", expVal, v.Metric.Metric, v.Values)
|
||||
return fmt.Errorf("expected %v for %s but got %v", expVal, v.Metric, v.Values)
|
||||
}
|
||||
}
|
||||
seen[fp] = true
|
||||
|
@ -369,22 +369,22 @@ func (ev *evalCmd) compareResult(result Value) error {
|
|||
}
|
||||
}
|
||||
|
||||
case Vector:
|
||||
case model.Vector:
|
||||
if !ev.instant {
|
||||
fmt.Errorf("received instant result on range evaluation")
|
||||
}
|
||||
seen := map[model.Fingerprint]bool{}
|
||||
for pos, v := range val {
|
||||
fp := v.Metric.Metric.Fingerprint()
|
||||
fp := v.Metric.Fingerprint()
|
||||
if _, ok := ev.metrics[fp]; !ok {
|
||||
return fmt.Errorf("unexpected metric %s in result", v.Metric.Metric)
|
||||
return fmt.Errorf("unexpected metric %s in result", v.Metric)
|
||||
}
|
||||
exp := ev.expected[fp]
|
||||
if ev.ordered && exp.pos != pos+1 {
|
||||
return fmt.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric.Metric, exp.vals, exp.pos, pos+1)
|
||||
return fmt.Errorf("expected metric %s with %v at position %d but was at %d", v.Metric, exp.vals, exp.pos, pos+1)
|
||||
}
|
||||
if !almostEqual(float64(exp.vals[0].value), float64(v.Value)) {
|
||||
return fmt.Errorf("expected %v for %s but got %v", exp.vals[0].value, v.Metric.Metric, v.Value)
|
||||
return fmt.Errorf("expected %v for %s but got %v", exp.vals[0].value, v.Metric, v.Value)
|
||||
}
|
||||
|
||||
seen[fp] = true
|
||||
|
@ -395,7 +395,7 @@ func (ev *evalCmd) compareResult(result Value) error {
|
|||
}
|
||||
}
|
||||
|
||||
case *Scalar:
|
||||
case *model.Scalar:
|
||||
if !almostEqual(float64(ev.expected[0].vals[0].value), float64(val.Value)) {
|
||||
return fmt.Errorf("expected scalar %v but got %v", val.Value, ev.expected[0].vals[0].value)
|
||||
}
|
||||
|
|
|
@ -77,8 +77,8 @@ type Alert struct {
|
|||
}
|
||||
|
||||
// sample returns a Sample suitable for recording the alert.
|
||||
func (a Alert) sample(timestamp model.Time, value model.SampleValue) *promql.Sample {
|
||||
recordedMetric := model.Metric{}
|
||||
func (a Alert) sample(timestamp model.Time, value model.SampleValue) *model.Sample {
|
||||
recordedMetric := make(model.Metric, len(a.Labels)+3)
|
||||
for label, value := range a.Labels {
|
||||
recordedMetric[label] = value
|
||||
}
|
||||
|
@ -87,11 +87,8 @@ func (a Alert) sample(timestamp model.Time, value model.SampleValue) *promql.Sam
|
|||
recordedMetric[alertNameLabel] = model.LabelValue(a.Name)
|
||||
recordedMetric[alertStateLabel] = model.LabelValue(a.State.String())
|
||||
|
||||
return &promql.Sample{
|
||||
Metric: model.COWMetric{
|
||||
Metric: recordedMetric,
|
||||
Copied: true,
|
||||
},
|
||||
return &model.Sample{
|
||||
Metric: recordedMetric,
|
||||
Value: value,
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
|
@ -152,7 +149,7 @@ func (rule *AlertingRule) Name() string {
|
|||
|
||||
// eval evaluates the rule expression and then creates pending alerts and fires
|
||||
// or removes previously pending alerts accordingly.
|
||||
func (rule *AlertingRule) eval(timestamp model.Time, engine *promql.Engine) (promql.Vector, error) {
|
||||
func (rule *AlertingRule) eval(timestamp model.Time, engine *promql.Engine) (model.Vector, error) {
|
||||
query, err := engine.NewInstantQuery(rule.vector.String(), timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -169,11 +166,11 @@ func (rule *AlertingRule) eval(timestamp model.Time, engine *promql.Engine) (pro
|
|||
// or update the expression value for existing elements.
|
||||
resultFPs := map[model.Fingerprint]struct{}{}
|
||||
for _, sample := range exprResult {
|
||||
fp := sample.Metric.Metric.Fingerprint()
|
||||
fp := sample.Metric.Fingerprint()
|
||||
resultFPs[fp] = struct{}{}
|
||||
|
||||
if alert, ok := rule.activeAlerts[fp]; !ok {
|
||||
labels := model.LabelSet(sample.Metric.Metric.Clone())
|
||||
labels := model.LabelSet(sample.Metric.Clone())
|
||||
labels = labels.Merge(rule.labels)
|
||||
if _, ok := labels[model.MetricNameLabel]; ok {
|
||||
delete(labels, model.MetricNameLabel)
|
||||
|
@ -190,7 +187,7 @@ func (rule *AlertingRule) eval(timestamp model.Time, engine *promql.Engine) (pro
|
|||
}
|
||||
}
|
||||
|
||||
vector := promql.Vector{}
|
||||
var vector model.Vector
|
||||
|
||||
// Check if any pending alerts should be removed or fire now. Write out alert timeseries.
|
||||
for fp, activeAlert := range rule.activeAlerts {
|
||||
|
|
|
@ -80,7 +80,7 @@ type Rule interface {
|
|||
// Name returns the name of the rule.
|
||||
Name() string
|
||||
// Eval evaluates the rule, including any associated recording or alerting actions.
|
||||
eval(model.Time, *promql.Engine) (promql.Vector, error)
|
||||
eval(model.Time, *promql.Engine) (model.Vector, error)
|
||||
// String returns a human-readable string representation of the rule.
|
||||
String() string
|
||||
// HTMLSnippet returns a human-readable string representation of the rule,
|
||||
|
@ -273,11 +273,7 @@ func (m *Manager) runIteration() {
|
|||
}
|
||||
|
||||
for _, s := range vector {
|
||||
m.sampleAppender.Append(&model.Sample{
|
||||
Metric: s.Metric.Metric,
|
||||
Value: s.Value,
|
||||
Timestamp: s.Timestamp,
|
||||
})
|
||||
m.sampleAppender.Append(s)
|
||||
}
|
||||
}(rule)
|
||||
}
|
||||
|
|
|
@ -43,38 +43,44 @@ func NewRecordingRule(name string, vector promql.Expr, labels model.LabelSet) *R
|
|||
func (rule RecordingRule) Name() string { return rule.name }
|
||||
|
||||
// eval evaluates the rule and then overrides the metric names and labels accordingly.
|
||||
func (rule RecordingRule) eval(timestamp model.Time, engine *promql.Engine) (promql.Vector, error) {
|
||||
func (rule RecordingRule) eval(timestamp model.Time, engine *promql.Engine) (model.Vector, error) {
|
||||
query, err := engine.NewInstantQuery(rule.vector.String(), timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := query.Exec()
|
||||
var vector promql.Vector
|
||||
var (
|
||||
result = query.Exec()
|
||||
vector model.Vector
|
||||
)
|
||||
switch result.Value.(type) {
|
||||
case promql.Vector:
|
||||
case model.Vector:
|
||||
vector, err = result.Vector()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *promql.Scalar:
|
||||
case *model.Scalar:
|
||||
scalar, err := result.Scalar()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vector = promql.Vector{&promql.Sample{Value: scalar.Value, Timestamp: scalar.Timestamp}}
|
||||
vector = model.Vector{&model.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.
|
||||
for _, sample := range vector {
|
||||
sample.Metric.Set(model.MetricNameLabel, model.LabelValue(rule.name))
|
||||
sample.Metric[model.MetricNameLabel] = model.LabelValue(rule.name)
|
||||
|
||||
for label, value := range rule.labels {
|
||||
if value == "" {
|
||||
sample.Metric.Del(label)
|
||||
delete(sample.Metric, label)
|
||||
} else {
|
||||
sample.Metric.Set(label, value)
|
||||
sample.Metric[label] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,21 +27,21 @@ func TestMetric(t *testing.T) {
|
|||
|
||||
scenarios := []struct {
|
||||
fn func(*Metric)
|
||||
out Metric
|
||||
out model.Metric
|
||||
}{
|
||||
{
|
||||
fn: func(cm *etric) {
|
||||
fn: func(cm *Metric) {
|
||||
cm.Del("to_delete")
|
||||
},
|
||||
out: Metric{
|
||||
out: model.Metric{
|
||||
"to_change": "test2",
|
||||
},
|
||||
},
|
||||
{
|
||||
fn: func(cm *COWMetric) {
|
||||
fn: func(cm *Metric) {
|
||||
cm.Set("to_change", "changed")
|
||||
},
|
||||
out: Metric{
|
||||
out: model.Metric{
|
||||
"to_delete": "test1",
|
||||
"to_change": "changed",
|
||||
},
|
||||
|
|
|
@ -64,24 +64,21 @@ func query(q string, timestamp model.Time, queryEngine *promql.Engine) (queryRes
|
|||
if res.Err != nil {
|
||||
return nil, res.Err
|
||||
}
|
||||
var vector promql.Vector
|
||||
var vector model.Vector
|
||||
|
||||
switch v := res.Value.(type) {
|
||||
case promql.Matrix:
|
||||
case model.Matrix:
|
||||
return nil, errors.New("matrix return values not supported")
|
||||
case promql.Vector:
|
||||
case model.Vector:
|
||||
vector = v
|
||||
case *promql.Scalar:
|
||||
vector = promql.Vector{&promql.Sample{
|
||||
case *model.Scalar:
|
||||
vector = model.Vector{&model.Sample{
|
||||
Value: v.Value,
|
||||
Timestamp: v.Timestamp,
|
||||
}}
|
||||
case *promql.String:
|
||||
vector = promql.Vector{&promql.Sample{
|
||||
Metric: model.COWMetric{
|
||||
Metric: model.Metric{"__value__": model.LabelValue(v.Value)},
|
||||
Copied: true,
|
||||
},
|
||||
case *model.String:
|
||||
vector = model.Vector{&model.Sample{
|
||||
Metric: model.Metric{"__value__": model.LabelValue(v.Value)},
|
||||
Timestamp: v.Timestamp,
|
||||
}}
|
||||
default:
|
||||
|
@ -96,7 +93,7 @@ func query(q string, timestamp model.Time, queryEngine *promql.Engine) (queryRes
|
|||
Value: float64(v.Value),
|
||||
Labels: make(map[string]string),
|
||||
}
|
||||
for label, value := range v.Metric.Metric {
|
||||
for label, value := range v.Metric {
|
||||
s.Labels[string(label)] = string(value)
|
||||
}
|
||||
result[n] = &s
|
||||
|
|
|
@ -26,8 +26,6 @@ import (
|
|||
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/log"
|
||||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
)
|
||||
|
||||
// Enables cross-site script calls.
|
||||
|
@ -89,15 +87,15 @@ func (api *API) Query(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
log.Debugf("Instant query: %s\nQuery stats:\n%s\n", expr, query.Stats())
|
||||
|
||||
if vec, ok := res.Value.(promql.Vector); ok {
|
||||
if vec, ok := res.Value.(model.Vector); ok {
|
||||
respondJSON(w, plainVec(vec))
|
||||
return
|
||||
}
|
||||
if sca, ok := res.Value.(*promql.Scalar); ok {
|
||||
if sca, ok := res.Value.(*model.Scalar); ok {
|
||||
respondJSON(w, (*plainScalar)(sca))
|
||||
return
|
||||
}
|
||||
if str, ok := res.Value.(*promql.String); ok {
|
||||
if str, ok := res.Value.(*model.String); ok {
|
||||
respondJSON(w, (*plainString)(str))
|
||||
return
|
||||
}
|
||||
|
@ -107,10 +105,10 @@ func (api *API) Query(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// plainVec is an indirection that hides the original MarshalJSON method
|
||||
// which does not fit the response format for the legacy API.
|
||||
type plainVec promql.Vector
|
||||
type plainVec model.Vector
|
||||
|
||||
func (pv plainVec) MarshalJSON() ([]byte, error) {
|
||||
type plainSmpl promql.Sample
|
||||
type plainSmpl model.Sample
|
||||
|
||||
v := make([]*plainSmpl, len(pv))
|
||||
for i, sv := range pv {
|
||||
|
@ -120,8 +118,8 @@ func (pv plainVec) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(&v)
|
||||
}
|
||||
|
||||
func (pv plainVec) Type() promql.ExprType {
|
||||
return promql.ExprVector
|
||||
func (pv plainVec) Type() model.ValueType {
|
||||
return model.ValVector
|
||||
}
|
||||
|
||||
func (pv plainVec) String() string {
|
||||
|
@ -130,15 +128,15 @@ func (pv plainVec) String() string {
|
|||
|
||||
// plainScalar is an indirection that hides the original MarshalJSON method
|
||||
// which does not fit the response format for the legacy API.
|
||||
type plainScalar promql.Scalar
|
||||
type plainScalar model.Scalar
|
||||
|
||||
func (ps plainScalar) MarshalJSON() ([]byte, error) {
|
||||
s := strconv.FormatFloat(float64(ps.Value), 'f', -1, 64)
|
||||
return json.Marshal(&s)
|
||||
}
|
||||
|
||||
func (plainScalar) Type() promql.ExprType {
|
||||
return promql.ExprScalar
|
||||
func (plainScalar) Type() model.ValueType {
|
||||
return model.ValScalar
|
||||
}
|
||||
|
||||
func (plainScalar) String() string {
|
||||
|
@ -147,10 +145,10 @@ func (plainScalar) String() string {
|
|||
|
||||
// plainString is an indirection that hides the original MarshalJSON method
|
||||
// which does not fit the response format for the legacy API.
|
||||
type plainString promql.String
|
||||
type plainString model.String
|
||||
|
||||
func (pv plainString) Type() promql.ExprType {
|
||||
return promql.ExprString
|
||||
func (pv plainString) Type() model.ValueType {
|
||||
return model.ValString
|
||||
}
|
||||
|
||||
func (pv plainString) String() string {
|
||||
|
@ -257,7 +255,7 @@ func errorJSON(w io.Writer, err error) error {
|
|||
}
|
||||
|
||||
// RespondJSON converts the given data value to JSON and writes it to w.
|
||||
func respondJSON(w io.Writer, val promql.Value) error {
|
||||
func respondJSON(w io.Writer, val model.Value) error {
|
||||
data := struct {
|
||||
Type string `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
|
@ -268,7 +266,7 @@ func respondJSON(w io.Writer, val promql.Value) error {
|
|||
Version: jsonFormatVersion,
|
||||
}
|
||||
// TODO(fabxc): Adding MarshalJSON to promql.Values might be a good idea.
|
||||
if sc, ok := val.(*promql.Scalar); ok {
|
||||
if sc, ok := val.(*model.Scalar); ok {
|
||||
data.Value = sc.Value
|
||||
}
|
||||
enc := json.NewEncoder(w)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/storage/local"
|
||||
"github.com/prometheus/prometheus/storage/metric"
|
||||
"github.com/prometheus/prometheus/util/route"
|
||||
"github.com/prometheus/prometheus/util/strutil"
|
||||
)
|
||||
|
@ -98,8 +99,8 @@ func (api *API) Register(r *route.Router) {
|
|||
}
|
||||
|
||||
type queryData struct {
|
||||
ResultType promql.ExprType `json:"resultType"`
|
||||
Result promql.Value `json:"result"`
|
||||
ResultType model.ValueType `json:"resultType"`
|
||||
Result model.Value `json:"result"`
|
||||
}
|
||||
|
||||
func (api *API) query(r *http.Request) (interface{}, *apiError) {
|
||||
|
@ -187,7 +188,7 @@ func (api *API) series(r *http.Request) (interface{}, *apiError) {
|
|||
if len(r.Form["match[]"]) == 0 {
|
||||
return nil, &apiError{errorBadData, fmt.Errorf("no match[] parameter provided")}
|
||||
}
|
||||
res := map[model.Fingerprint]model.COWMetric{}
|
||||
res := map[model.Fingerprint]metric.Metric{}
|
||||
|
||||
for _, lm := range r.Form["match[]"] {
|
||||
matchers, err := promql.ParseMetricSelector(lm)
|
||||
|
|
|
@ -55,8 +55,8 @@ func TestEndpoints(t *testing.T) {
|
|||
"time": []string{"123.3"},
|
||||
},
|
||||
response: &queryData{
|
||||
ResultType: promql.ExprScalar,
|
||||
Result: &promql.Scalar{
|
||||
ResultType: model.ValScalar,
|
||||
Result: &model.Scalar{
|
||||
Value: 2,
|
||||
Timestamp: start.Add(123*time.Second + 300*time.Millisecond),
|
||||
},
|
||||
|
@ -69,8 +69,8 @@ func TestEndpoints(t *testing.T) {
|
|||
"time": []string{"1970-01-01T00:02:03Z"},
|
||||
},
|
||||
response: &queryData{
|
||||
ResultType: promql.ExprScalar,
|
||||
Result: &promql.Scalar{
|
||||
ResultType: model.ValScalar,
|
||||
Result: &model.Scalar{
|
||||
Value: 0.333,
|
||||
Timestamp: start.Add(123 * time.Second),
|
||||
},
|
||||
|
@ -83,8 +83,8 @@ func TestEndpoints(t *testing.T) {
|
|||
"time": []string{"1970-01-01T01:02:03+01:00"},
|
||||
},
|
||||
response: &queryData{
|
||||
ResultType: promql.ExprScalar,
|
||||
Result: &promql.Scalar{
|
||||
ResultType: model.ValScalar,
|
||||
Result: &model.Scalar{
|
||||
Value: 0.333,
|
||||
Timestamp: start.Add(123 * time.Second),
|
||||
},
|
||||
|
@ -99,14 +99,15 @@ func TestEndpoints(t *testing.T) {
|
|||
"step": []string{"1"},
|
||||
},
|
||||
response: &queryData{
|
||||
ResultType: promql.ExprMatrix,
|
||||
Result: promql.Matrix{
|
||||
&promql.SampleStream{
|
||||
ResultType: model.ValMatrix,
|
||||
Result: model.Matrix{
|
||||
&model.SampleStream{
|
||||
Values: []model.SamplePair{
|
||||
{Value: 0, Timestamp: start},
|
||||
{Value: 1, Timestamp: start.Add(1 * time.Second)},
|
||||
{Value: 2, Timestamp: start.Add(2 * time.Second)},
|
||||
},
|
||||
Metric: model.Metric{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -312,7 +313,7 @@ func TestEndpoints(t *testing.T) {
|
|||
t.Fatalf("Expected error of type %q but got none", test.errType)
|
||||
}
|
||||
if !reflect.DeepEqual(resp, test.response) {
|
||||
t.Fatalf("Response does not match, expected:\n%#v\ngot:\n%#v", test.response, resp)
|
||||
t.Fatalf("Response does not match, expected:\n%+v\ngot:\n%+v", test.response, resp)
|
||||
}
|
||||
// Ensure that removed metrics are unindexed before the next request.
|
||||
suite.Storage().WaitForIndexing()
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/storage/local"
|
||||
"github.com/prometheus/prometheus/storage/metric"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
|
@ -33,7 +34,7 @@ type Federation struct {
|
|||
func (fed *Federation) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
req.ParseForm()
|
||||
|
||||
metrics := map[model.Fingerprint]model.COWMetric{}
|
||||
metrics := map[model.Fingerprint]metric.Metric{}
|
||||
|
||||
for _, s := range req.Form["match[]"] {
|
||||
matchers, err := promql.ParseMetricSelector(s)
|
||||
|
|
Loading…
Reference in a new issue