diff --git a/promql/functions.go b/promql/functions.go index 8d2a28307..d39bdbce4 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -228,6 +228,28 @@ func funcBottomk(ev *evaluator, args Expressions) model.Value { return vector(bottomk) } +// === clamp_max(vector model.ValVector, max Scalar) Vector === +func funcClampMax(ev *evaluator, args Expressions) model.Value { + vec := ev.evalVector(args[0]) + max := ev.evalFloat(args[1]) + for _, el := range vec { + el.Metric.Del(model.MetricNameLabel) + el.Value = model.SampleValue(math.Min(max, float64(el.Value))) + } + return vec +} + +// === clamp_min(vector model.ValVector, min Scalar) Vector === +func funcClampMin(ev *evaluator, args Expressions) model.Value { + vec := ev.evalVector(args[0]) + min := ev.evalFloat(args[1]) + for _, el := range vec { + el.Metric.Del(model.MetricNameLabel) + el.Value = model.SampleValue(math.Max(min, float64(el.Value))) + } + return vec +} + // === drop_common_labels(node model.ValVector) Vector === func funcDropCommonLabels(ev *evaluator, args Expressions) model.Value { vec := ev.evalVector(args[0]) @@ -751,6 +773,18 @@ var functions = map[string]*Function{ ReturnType: model.ValVector, Call: funcChanges, }, + "clamp_max": { + Name: "clamp_max", + ArgTypes: []model.ValueType{model.ValVector, model.ValScalar}, + ReturnType: model.ValVector, + Call: funcClampMax, + }, + "clamp_min": { + Name: "clamp_min", + ArgTypes: []model.ValueType{model.ValVector, model.ValScalar}, + ReturnType: model.ValVector, + Call: funcClampMin, + }, "count_over_time": { Name: "count_over_time", ArgTypes: []model.ValueType{model.ValMatrix}, diff --git a/promql/testdata/functions.test b/promql/testdata/functions.test index 3972053df..de9854d60 100644 --- a/promql/testdata/functions.test +++ b/promql/testdata/functions.test @@ -170,3 +170,26 @@ eval instant at 0m vector(1) eval instant at 60m vector(time()) {} 3600 + +clear + +# Tests for clamp_max and clamp_min(). +load 5m + test_clamp{src="clamp-a"} -50 + test_clamp{src="clamp-b"} 0 + test_clamp{src="clamp-c"} 100 + +eval instant at 0m clamp_max(test_clamp, 75) + {src="clamp-a"} -50 + {src="clamp-b"} 0 + {src="clamp-c"} 75 + +eval instant at 0m clamp_min(test_clamp, -25) + {src="clamp-a"} -25 + {src="clamp-b"} 0 + {src="clamp-c"} 100 + +eval instant at 0m clamp_max(clamp_min(test_clamp, -20), 70) + {src="clamp-a"} -20 + {src="clamp-b"} 0 + {src="clamp-c"} 70