From f1f66fbed1f41cbf34f600de112efe2a612facde Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Mon, 12 Jan 2026 17:27:32 +0800 Subject: [PATCH] feat(monitor): delta reducer (#24063) --- pkg/apis/monitor/reducer.go | 3 +- pkg/apis/monitor/unifiedmonitor_query.go | 1 + pkg/monitor/alerting/conditions/evaluator.go | 4 +-- .../alerting/conditions/mathreducer.go | 2 ++ pkg/monitor/alerting/conditions/reducer.go | 29 +++++++++++++++++++ pkg/monitor/dbinit/measurements/system.go | 3 ++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/pkg/apis/monitor/reducer.go b/pkg/apis/monitor/reducer.go index 38cecaed08..a2a57171b2 100644 --- a/pkg/apis/monitor/reducer.go +++ b/pkg/apis/monitor/reducer.go @@ -27,6 +27,7 @@ const ( REDUCER_LAST ReducerType = "last" REDUCER_MEDIAN ReducerType = "median" REDUCER_DIFF ReducerType = "diff" + REDUCER_DELTA ReducerType = "delta" REDUCER_PERCENT_DIFF ReducerType = "percent_diff" REDUCER_COUNT_NON_NULL ReducerType = "count_non_null" REDUCER_PERCENTILE ReducerType = "percentile" @@ -37,7 +38,7 @@ var ValidateReducerTypes = sets.NewString() func init() { for _, rt := range []ReducerType{REDUCER_AVG, REDUCER_SUM, REDUCER_MIN, REDUCER_MAX, REDUCER_COUNT, REDUCER_LAST, REDUCER_MEDIAN, REDUCER_DIFF, - REDUCER_PERCENT_DIFF, REDUCER_COUNT_NON_NULL, REDUCER_PERCENTILE} { + REDUCER_DELTA, REDUCER_PERCENT_DIFF, REDUCER_COUNT_NON_NULL, REDUCER_PERCENTILE} { ValidateReducerTypes.Insert(string(rt)) } } diff --git a/pkg/apis/monitor/unifiedmonitor_query.go b/pkg/apis/monitor/unifiedmonitor_query.go index 295a36d99e..01f0e1124b 100644 --- a/pkg/apis/monitor/unifiedmonitor_query.go +++ b/pkg/apis/monitor/unifiedmonitor_query.go @@ -62,6 +62,7 @@ var ( "last": "Latest value", "median": "median", "diff": "The difference between the latest value and the oldest value. The judgment basis value must be legal", + "delta": "The signed difference between the latest value and the oldest value (can be positive or negative)", "percent_diff": "The difference between the new value and the old value,based on the percentage of the old value", } ) diff --git a/pkg/monitor/alerting/conditions/evaluator.go b/pkg/monitor/alerting/conditions/evaluator.go index 398874aa12..c9bb5f41f7 100644 --- a/pkg/monitor/alerting/conditions/evaluator.go +++ b/pkg/monitor/alerting/conditions/evaluator.go @@ -63,11 +63,11 @@ func (e *thresholdEvaluator) Eval(reducedValue *float64) bool { val := *reducedValue switch e.Type { case "gt": - return val >= e.Threshold + return val > e.Threshold case "eq": return val == e.Threshold case "lt": - return val <= e.Threshold + return val < e.Threshold } return false diff --git a/pkg/monitor/alerting/conditions/mathreducer.go b/pkg/monitor/alerting/conditions/mathreducer.go index 42ddee25ea..0f0f0fdd6c 100644 --- a/pkg/monitor/alerting/conditions/mathreducer.go +++ b/pkg/monitor/alerting/conditions/mathreducer.go @@ -148,6 +148,8 @@ func (s *mathReducer) Reduce(series *monitor.TimeSeries) (*float64, []string) { } case "diff": allNull, value = calculateDiff(series, allNull, value, diff) + case "delta": + allNull, value = calculateDelta(series, allNull, value) case "percent_diff": allNull, value = calculateDiff(series, allNull, value, percentDiff) case "count_non_null": diff --git a/pkg/monitor/alerting/conditions/reducer.go b/pkg/monitor/alerting/conditions/reducer.go index 4e64df0073..317155bd8d 100644 --- a/pkg/monitor/alerting/conditions/reducer.go +++ b/pkg/monitor/alerting/conditions/reducer.go @@ -137,6 +137,8 @@ func (s *queryReducer) Reduce(series *monitor.TimeSeries) (*float64, []string) { } case monitor.REDUCER_DIFF: allNull, value = calculateDiff(series, allNull, value, diff) + case monitor.REDUCER_DELTA: + allNull, value = calculateDelta(series, allNull, value) case monitor.REDUCER_PERCENT_DIFF: allNull, value = calculateDiff(series, allNull, value, percentDiff) case monitor.REDUCER_COUNT_NON_NULL: @@ -226,6 +228,33 @@ var percentDiff = func(newest, oldest float64) float64 { return (newest - oldest) / oldest * 100 } +func calculateDelta(series *monitor.TimeSeries, allNull bool, value float64) (bool, float64) { + var ( + points = series.Points + first float64 + i int + ) + // get the newest point + for i = len(points) - 1; i >= 0; i-- { + if points[i].IsValid() { + allNull = false + first = points[i].Value() + break + } + } + if i >= 1 { + // get the oldest point + for i := 0; i < len(points); i++ { + if points[i].IsValid() { + allNull = false + value = first - points[i].Value() + break + } + } + } + return allNull, value +} + func NewAlertReducer(cond *monitor.Condition) (Reducer, error) { if len(cond.Operators) == 0 { return newSimpleReducer(cond), nil diff --git a/pkg/monitor/dbinit/measurements/system.go b/pkg/monitor/dbinit/measurements/system.go index a685ae176b..b397325c40 100644 --- a/pkg/monitor/dbinit/measurements/system.go +++ b/pkg/monitor/dbinit/measurements/system.go @@ -42,5 +42,8 @@ var system = SMeasurement{ { "load15_pcore", "Loadavg load15 per cpu core", monitor.METRIC_UNIT_NULL, }, + { + "uptime", "System uptime", monitor.METRIC_UNIT_NULL, + }, }, }