diff --git a/promql/functions.go b/promql/functions.go index 6103dbd38..68d30ec43 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -532,6 +532,33 @@ func funcResets(ev *evaluator, args Expressions) Value { return out } +// === changes(matrix ExprMatrix) Vector === +func funcChanges(ev *evaluator, args Expressions) Value { + in := ev.evalMatrix(args[0]) + out := make(Vector, 0, len(in)) + + for _, samples := range in { + changes := 0 + prev := clientmodel.SampleValue(samples.Values[0].Value) + for _, sample := range samples.Values[1:] { + current := sample.Value + if current != prev { + changes++ + } + prev = current + } + + rs := &Sample{ + Metric: samples.Metric, + Value: clientmodel.SampleValue(changes), + Timestamp: ev.Timestamp, + } + rs.Metric.Delete(clientmodel.MetricNameLabel) + out = append(out, rs) + } + return out +} + var functions = map[string]*Function{ "abs": { Name: "abs", @@ -563,6 +590,12 @@ var functions = map[string]*Function{ ReturnType: ExprVector, Call: funcCeil, }, + "changes": { + Name: "changes", + ArgTypes: []ExprType{ExprMatrix}, + ReturnType: ExprVector, + Call: funcChanges, + }, "count_over_time": { Name: "count_over_time", ArgTypes: []ExprType{ExprMatrix}, diff --git a/promql/testdata/functions.test b/promql/testdata/functions.test index e3c5687f9..143f8deb5 100644 --- a/promql/testdata/functions.test +++ b/promql/testdata/functions.test @@ -1,21 +1,51 @@ +# Testdata for resets() and changes(). load 5m http_requests{path="/foo"} 1 2 3 0 1 0 0 1 2 0 http_requests{path="/bar"} 1 2 3 4 5 1 2 3 4 5 + http_requests{path="/biz"} 0 0 0 0 0 1 1 1 1 1 +# Tests for resets(). eval instant at 50m resets(http_requests[5m]) {path="/foo"} 0 {path="/bar"} 0 + {path="/biz"} 0 eval instant at 50m resets(http_requests[20m]) {path="/foo"} 1 {path="/bar"} 0 + {path="/biz"} 0 eval instant at 50m resets(http_requests[30m]) {path="/foo"} 2 {path="/bar"} 1 + {path="/biz"} 0 eval instant at 50m resets(http_requests[50m]) {path="/foo"} 3 {path="/bar"} 1 + {path="/biz"} 0 eval instant at 50m resets(nonexistent_metric[50m]) + +# Tests for changes(). +eval instant at 50m changes(http_requests[5m]) + {path="/foo"} 0 + {path="/bar"} 0 + {path="/biz"} 0 + +eval instant at 50m changes(http_requests[20m]) + {path="/foo"} 3 + {path="/bar"} 3 + {path="/biz"} 0 + +eval instant at 50m changes(http_requests[30m]) + {path="/foo"} 4 + {path="/bar"} 5 + {path="/biz"} 1 + +eval instant at 50m changes(http_requests[50m]) + {path="/foo"} 8 + {path="/bar"} 9 + {path="/biz"} 1 + +eval instant at 50m changes(nonexistent_metric[50m])