Switch promql types to common/model

This commit is contained in:
Fabian Reinartz 2015-08-24 18:04:41 +02:00
parent e061595352
commit d6b8da8d43
18 changed files with 449 additions and 556 deletions

4
Godeps/Godeps.json generated
View file

@ -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",

View file

@ -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 {

View file

@ -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() {}

View file

@ -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,

View file

@ -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{} {

View file

@ -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)
}

View file

@ -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, "")

View file

@ -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
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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)
}

View file

@ -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
}
}
}

View file

@ -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",
},

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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()

View file

@ -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)