Export members of EvalNodeHelper to facilitate usage in external functions (#7860)

Signed-off-by: Vijay Samuel <vjsamuel@ebay.com>
This commit is contained in:
Vijay Samuel 2020-08-27 11:30:10 -07:00 committed by GitHub
parent c806262206
commit 00ee73ef91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 98 deletions

View file

@ -792,13 +792,13 @@ func (ev *evaluator) Eval(expr parser.Expr) (v parser.Value, ws storage.Warnings
// EvalNodeHelper stores extra information and caches for evaluating a single node across steps.
type EvalNodeHelper struct {
// Evaluation timestamp.
ts int64
Ts int64
// Vector that can be used for output.
out Vector
Out Vector
// Caches.
// dropMetricName and label_*.
dmn map[uint64]labels.Labels
// DropMetricName and label_*.
Dmn map[uint64]labels.Labels
// signatureFunc.
sigf map[string]string
// funcHistogramQuantile.
@ -816,24 +816,24 @@ type EvalNodeHelper struct {
resultMetric map[string]labels.Labels
}
// dropMetricName is a cached version of dropMetricName.
func (enh *EvalNodeHelper) dropMetricName(l labels.Labels) labels.Labels {
if enh.dmn == nil {
enh.dmn = make(map[uint64]labels.Labels, len(enh.out))
// DropMetricName is a cached version of DropMetricName.
func (enh *EvalNodeHelper) DropMetricName(l labels.Labels) labels.Labels {
if enh.Dmn == nil {
enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
}
h := l.Hash()
ret, ok := enh.dmn[h]
ret, ok := enh.Dmn[h]
if ok {
return ret
}
ret = dropMetricName(l)
enh.dmn[h] = ret
enh.Dmn[h] = ret
return ret
}
func (enh *EvalNodeHelper) signatureFunc(on bool, names ...string) func(labels.Labels) string {
if enh.sigf == nil {
enh.sigf = make(map[string]string, len(enh.out))
enh.sigf = make(map[string]string, len(enh.Out))
}
f := signatureFunc(on, enh.lblBuf, names...)
return func(l labels.Labels) string {
@ -885,7 +885,7 @@ func (ev *evaluator) rangeEval(f func([]parser.Value, *EvalNodeHelper) (Vector,
biggestLen = len(matrixes[i])
}
}
enh := &EvalNodeHelper{out: make(Vector, 0, biggestLen)}
enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)}
seriess := make(map[uint64]Series, biggestLen) // Output series by series hash.
tempNumSamples := ev.currentSamples
for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval {
@ -916,12 +916,12 @@ func (ev *evaluator) rangeEval(f func([]parser.Value, *EvalNodeHelper) (Vector,
args[i] = vectors[i]
}
// Make the function call.
enh.ts = ts
enh.Ts = ts
result, ws := f(args, enh)
if result.ContainsSameLabelset() {
ev.errorf("vector cannot contain metrics with the same labelset")
}
enh.out = result[:0] // Reuse result vector.
enh.Out = result[:0] // Reuse result vector.
warnings = append(warnings, ws...)
ev.currentSamples += len(result)
@ -1030,7 +1030,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
vs, ok := e.Args[0].(*parser.VectorSelector)
if ok {
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
val, ws := ev.vectorSelector(vs, enh.ts)
val, ws := ev.vectorSelector(vs, enh.Ts)
return call([]parser.Value{val}, e.Args, enh), ws
})
}
@ -1101,7 +1101,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
points := getPointSlice(16)
inMatrix := make(Matrix, 1)
inArgs[matrixArgIndex] = inMatrix
enh := &EvalNodeHelper{out: make(Vector, 0, 1)}
enh := &EvalNodeHelper{Out: make(Vector, 0, 1)}
// Process all the calls for one time series at a time.
it := storage.NewBuffer(selRange)
for i, s := range selVS.Series {
@ -1134,10 +1134,10 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
continue
}
inMatrix[0].Points = points
enh.ts = ts
enh.Ts = ts
// Make the function call.
outVec := call(inArgs, e.Args, enh)
enh.out = outVec[:0]
enh.Out = outVec[:0]
if len(outVec) > 0 {
ss.Points = append(ss.Points, Point{V: outVec[0].Point.V, T: ts})
}
@ -1227,7 +1227,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
case lt == parser.ValueTypeScalar && rt == parser.ValueTypeScalar:
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
val := scalarBinop(e.Op, v[0].(Vector)[0].Point.V, v[1].(Vector)[0].Point.V)
return append(enh.out, Sample{Point: Point{V: val}}), nil
return append(enh.Out, Sample{Point: Point{V: val}}), nil
}, e.LHS, e.RHS)
case lt == parser.ValueTypeVector && rt == parser.ValueTypeVector:
switch e.Op {
@ -1262,7 +1262,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
case *parser.NumberLiteral:
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
return append(enh.out, Sample{Point: Point{V: e.Val}}), nil
return append(enh.Out, Sample{Point: Point{V: e.Val}}), nil
})
case *parser.VectorSelector:
@ -1530,10 +1530,10 @@ func (ev *evaluator) VectorAnd(lhs, rhs Vector, matching *parser.VectorMatching,
for _, ls := range lhs {
// If there's a matching entry in the right-hand side Vector, add the sample.
if _, ok := rightSigs[sigf(ls.Metric)]; ok {
enh.out = append(enh.out, ls)
enh.Out = append(enh.Out, ls)
}
}
return enh.out
return enh.Out
}
func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
@ -1546,15 +1546,15 @@ func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching,
// Add everything from the left-hand-side Vector.
for _, ls := range lhs {
leftSigs[sigf(ls.Metric)] = struct{}{}
enh.out = append(enh.out, ls)
enh.Out = append(enh.Out, ls)
}
// Add all right-hand side elements which have not been added from the left-hand side.
for _, rs := range rhs {
if _, ok := leftSigs[sigf(rs.Metric)]; !ok {
enh.out = append(enh.out, rs)
enh.Out = append(enh.Out, rs)
}
}
return enh.out
return enh.Out
}
func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
@ -1570,10 +1570,10 @@ func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatchi
for _, ls := range lhs {
if _, ok := rightSigs[sigf(ls.Metric)]; !ok {
enh.out = append(enh.out, ls)
enh.Out = append(enh.Out, ls)
}
}
return enh.out
return enh.Out
}
// VectorBinop evaluates a binary operation between two Vectors, excluding set operators.
@ -1592,7 +1592,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
// All samples from the rhs hashed by the matching label/values.
if enh.rightSigs == nil {
enh.rightSigs = make(map[string]Sample, len(enh.out))
enh.rightSigs = make(map[string]Sample, len(enh.Out))
} else {
for k := range enh.rightSigs {
delete(enh.rightSigs, k)
@ -1657,7 +1657,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
}
metric := resultMetric(ls.Metric, rs.Metric, op, matching, enh)
if returnBool {
metric = enh.dropMetricName(metric)
metric = enh.DropMetricName(metric)
}
insertedSigs, exists := matchedSigs[sig]
if matching.Card == parser.CardOneToOne {
@ -1680,12 +1680,12 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
insertedSigs[insertSig] = struct{}{}
}
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: metric,
Point: Point{V: value},
})
}
return enh.out
return enh.Out
}
func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) string {
@ -1704,7 +1704,7 @@ func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) strin
// binary operation and the matching options.
func resultMetric(lhs, rhs labels.Labels, op parser.ItemType, matching *parser.VectorMatching, enh *EvalNodeHelper) labels.Labels {
if enh.resultMetric == nil {
enh.resultMetric = make(map[string]labels.Labels, len(enh.out))
enh.resultMetric = make(map[string]labels.Labels, len(enh.Out))
}
if enh.lb == nil {
@ -1784,12 +1784,12 @@ func (ev *evaluator) VectorscalarBinop(op parser.ItemType, lhs Vector, rhs Scala
if keep {
lhsSample.V = value
if shouldDropMetricName(op) || returnBool {
lhsSample.Metric = enh.dropMetricName(lhsSample.Metric)
lhsSample.Metric = enh.DropMetricName(lhsSample.Metric)
}
enh.out = append(enh.out, lhsSample)
enh.Out = append(enh.Out, lhsSample)
}
}
return enh.out
return enh.Out
}
func dropMetricName(l labels.Labels) labels.Labels {
@ -2069,7 +2069,7 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// The heap keeps the lowest value on top, so reverse it.
sort.Sort(sort.Reverse(aggr.heap))
for _, v := range aggr.heap {
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: v.Metric,
Point: Point{V: v.V},
})
@ -2080,7 +2080,7 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// The heap keeps the lowest value on top, so reverse it.
sort.Sort(sort.Reverse(aggr.reverseHeap))
for _, v := range aggr.reverseHeap {
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: v.Metric,
Point: Point{V: v.V},
})
@ -2094,12 +2094,12 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// For other aggregations, we already have the right value.
}
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: aggr.labels,
Point: Point{V: aggr.value},
})
}
return enh.out
return enh.Out
}
// btos returns 1 if b is true, 0 otherwise.

View file

@ -36,7 +36,7 @@ import (
// value,and nil for strings.
// args are the original arguments to the function, where you can access
// matrixSelectors, vectorSelectors, and StringLiterals.
// enh.out is a pre-allocated empty vector that you may use to accumulate
// enh.Out is a pre-allocated empty vector that you may use to accumulate
// output before returning it. The vectors in vals should not be returned.a
// Range vector functions need only return a vector with the right value,
// the metric and timestamp are not needed.
@ -48,7 +48,7 @@ type FunctionCall func(vals []parser.Value, args parser.Expressions, enh *EvalNo
// === time() float64 ===
func funcTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return Vector{Sample{Point: Point{
V: float64(enh.ts) / 1000,
V: float64(enh.Ts) / 1000,
}}}
}
@ -62,14 +62,14 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
var (
samples = vals[0].(Matrix)[0]
rangeStart = enh.ts - durationMilliseconds(ms.Range+vs.Offset)
rangeEnd = enh.ts - durationMilliseconds(vs.Offset)
rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset)
rangeEnd = enh.Ts - durationMilliseconds(vs.Offset)
)
// No sense in trying to compute a rate without at least two points. Drop
// this Vector element.
if len(samples.Points) < 2 {
return enh.out
return enh.Out
}
var (
counterCorrection float64
@ -126,7 +126,7 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
resultValue = resultValue / ms.Range.Seconds()
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: resultValue},
})
}
@ -148,12 +148,12 @@ func funcIncrease(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
// === irate(node parser.ValueTypeMatrix) Vector ===
func funcIrate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return instantValue(vals, enh.out, true)
return instantValue(vals, enh.Out, true)
}
// === idelta(node model.ValMatrix) Vector ===
func funcIdelta(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return instantValue(vals, enh.out, false)
return instantValue(vals, enh.Out, false)
}
func instantValue(vals []parser.Value, out Vector, isRate bool) Vector {
@ -234,7 +234,7 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
// Can't do the smoothing operation with less than two points.
if l < 2 {
return enh.out
return enh.Out
}
var s0, s1, b float64
@ -256,7 +256,7 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
s0, s1 = s1, x+y
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: s1},
})
}
@ -284,12 +284,12 @@ func funcClampMax(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
vec := vals[0].(Vector)
max := vals[1].(Vector)[0].Point.V
for _, el := range vec {
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: math.Min(max, el.V)},
})
}
return enh.out
return enh.Out
}
// === clamp_min(Vector parser.ValueTypeVector, min Scalar) Vector ===
@ -297,12 +297,12 @@ func funcClampMin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
vec := vals[0].(Vector)
min := vals[1].(Vector)[0].Point.V
for _, el := range vec {
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: math.Max(min, el.V)},
})
}
return enh.out
return enh.Out
}
// === round(Vector parser.ValueTypeVector, toNearest=1 Scalar) Vector ===
@ -319,23 +319,23 @@ func funcRound(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
for _, el := range vec {
v := math.Floor(el.V*toNearestInverse+0.5) / toNearestInverse
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: v},
})
}
return enh.out
return enh.Out
}
// === Scalar(node parser.ValueTypeVector) Scalar ===
func funcScalar(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
v := vals[0].(Vector)
if len(v) != 1 {
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: math.NaN()},
})
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: v[0].V},
})
}
@ -343,7 +343,7 @@ func funcScalar(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
func aggrOverTime(vals []parser.Value, enh *EvalNodeHelper, aggrFn func([]Point) float64) Vector {
el := vals[0].(Matrix)[0]
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: aggrFn(el.Points)},
})
}
@ -431,7 +431,7 @@ func funcQuantileOverTime(vals []parser.Value, args parser.Expressions, enh *Eva
for _, v := range el.Points {
values = append(values, Sample{Point: Point{V: v.V}})
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: quantile(q, values)},
})
}
@ -467,9 +467,9 @@ func funcStdvarOverTime(vals []parser.Value, args parser.Expressions, enh *EvalN
// === absent(Vector parser.ValueTypeVector) Vector ===
func funcAbsent(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
if len(vals[0].(Vector)) > 0 {
return enh.out
return enh.Out
}
return append(enh.out,
return append(enh.Out,
Sample{
Metric: createLabelsForAbsentFunction(args[0]),
Point: Point{V: 1},
@ -482,7 +482,7 @@ func funcAbsent(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
// Due to engine optimization, this function is only called when this condition is true.
// Then, the engine post-processes the results to get the expected output.
func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return append(enh.out,
return append(enh.Out,
Sample{
Point: Point{V: 1},
})
@ -490,12 +490,12 @@ func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalN
func simpleFunc(vals []parser.Value, enh *EvalNodeHelper, f func(float64) float64) Vector {
for _, el := range vals[0].(Vector) {
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: f(el.V)},
})
}
return enh.out
return enh.Out
}
// === abs(Vector parser.ValueTypeVector) Vector ===
@ -542,12 +542,12 @@ func funcLog10(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
vec := vals[0].(Vector)
for _, el := range vec {
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: float64(el.T) / 1000},
})
}
return enh.out
return enh.Out
}
// linearRegression performs a least-square linear regression analysis on the
@ -582,14 +582,14 @@ func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
// No sense in trying to compute a derivative without at least two points.
// Drop this Vector element.
if len(samples.Points) < 2 {
return enh.out
return enh.Out
}
// We pass in an arbitrary timestamp that is near the values in use
// to avoid floating point accuracy issues, see
// https://github.com/prometheus/prometheus/issues/2674
slope, _ := linearRegression(samples.Points, samples.Points[0].T)
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: slope},
})
}
@ -602,11 +602,11 @@ func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNo
// No sense in trying to predict anything without at least two points.
// Drop this Vector element.
if len(samples.Points) < 2 {
return enh.out
return enh.Out
}
slope, intercept := linearRegression(samples.Points, enh.ts)
slope, intercept := linearRegression(samples.Points, enh.Ts)
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: slope*duration + intercept},
})
}
@ -649,14 +649,14 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
for _, mb := range enh.signatureToMetricWithBuckets {
if len(mb.buckets) > 0 {
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: mb.metric,
Point: Point{V: bucketQuantile(q, mb.buckets)},
})
}
}
return enh.out
return enh.Out
}
// === resets(Matrix parser.ValueTypeMatrix) Vector ===
@ -673,7 +673,7 @@ func funcResets(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
prev = current
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: float64(resets)},
})
}
@ -692,7 +692,7 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp
prev = current
}
return append(enh.out, Sample{
return append(enh.Out, Sample{
Point: Point{V: float64(changes)},
})
}
@ -716,13 +716,13 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
if !model.LabelNameRE.MatchString(dst) {
panic(errors.Errorf("invalid destination label name in label_replace(): %s", dst))
}
enh.dmn = make(map[uint64]labels.Labels, len(enh.out))
enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
}
for _, el := range vector {
h := el.Metric.Hash()
var outMetric labels.Labels
if l, ok := enh.dmn[h]; ok {
if l, ok := enh.Dmn[h]; ok {
outMetric = l
} else {
srcVal := el.Metric.Get(src)
@ -730,7 +730,7 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
if indexes == nil {
// If there is no match, no replacement should take place.
outMetric = el.Metric
enh.dmn[h] = outMetric
enh.Dmn[h] = outMetric
} else {
res := enh.regex.ExpandString([]byte{}, repl, srcVal, indexes)
@ -739,21 +739,21 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
lb.Set(dst, string(res))
}
outMetric = lb.Labels()
enh.dmn[h] = outMetric
enh.Dmn[h] = outMetric
}
}
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: outMetric,
Point: Point{V: el.Point.V},
})
}
return enh.out
return enh.Out
}
// === Vector(s Scalar) Vector ===
func funcVector(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return append(enh.out,
return append(enh.Out,
Sample{
Metric: labels.Labels{},
Point: Point{V: vals[0].(Vector)[0].V},
@ -769,8 +769,8 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
srcLabels = make([]string, len(args)-3)
)
if enh.dmn == nil {
enh.dmn = make(map[uint64]labels.Labels, len(enh.out))
if enh.Dmn == nil {
enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
}
for i := 3; i < len(args); i++ {
@ -789,7 +789,7 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
for _, el := range vector {
h := el.Metric.Hash()
var outMetric labels.Labels
if l, ok := enh.dmn[h]; ok {
if l, ok := enh.Dmn[h]; ok {
outMetric = l
} else {
@ -807,35 +807,35 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
}
outMetric = lb.Labels()
enh.dmn[h] = outMetric
enh.Dmn[h] = outMetric
}
enh.out = append(enh.out, Sample{
enh.Out = append(enh.Out, Sample{
Metric: outMetric,
Point: Point{V: el.Point.V},
})
}
return enh.out
return enh.Out
}
// Common code for date related functions.
func dateWrapper(vals []parser.Value, enh *EvalNodeHelper, f func(time.Time) float64) Vector {
if len(vals) == 0 {
return append(enh.out,
return append(enh.Out,
Sample{
Metric: labels.Labels{},
Point: Point{V: f(time.Unix(enh.ts/1000, 0).UTC())},
Point: Point{V: f(time.Unix(enh.Ts/1000, 0).UTC())},
})
}
for _, el := range vals[0].(Vector) {
t := time.Unix(int64(el.V), 0).UTC()
enh.out = append(enh.out, Sample{
Metric: enh.dropMetricName(el.Metric),
enh.Out = append(enh.Out, Sample{
Metric: enh.DropMetricName(el.Metric),
Point: Point{V: f(t)},
})
}
return enh.out
return enh.Out
}
// === days_in_month(v Vector) Scalar ===