diff --git a/engine/engine_test.go b/engine/engine_test.go index ab11f4bc..4324c670 100644 --- a/engine/engine_test.go +++ b/engine/engine_test.go @@ -1500,6 +1500,24 @@ func TestQueriesAgainstOldEngine(t *testing.T) { end: time.Unix(3000, 0), step: 2 * time.Second, }, + { + name: "absent with present series", + load: `load 30s + absent{pod="nginx-1", series="1"} 0 + absent{pod="nginx-2", series="1"} 0`, + query: "absent(metric)", + start: time.Unix(0, 0), + end: time.Unix(3000, 0), + step: 10 * time.Second, + }, + { + name: "absent with non-present series", + load: "", + query: "absent(non_existent_metric)", + start: time.Unix(0, 0), + end: time.Unix(3000, 0), + step: 10 * time.Second, + }, } disableOptimizerOpts := []bool{true, false} @@ -2431,6 +2449,22 @@ func TestInstantQuery(t *testing.T) { http_requests_total{pod="nginx-2", series="1"} -10+1x50`, query: "sgn(http_requests_total)", }, + { + name: "absent with present series", + load: `load 30s + absent{pod="nginx-1", series="1"} 0 + absent{pod="nginx-2", series="1"} 0`, + query: "absent(metric)", + queryTime: time.Now(), + sortByLabels: true, + }, + { + name: "absent with non-present series", + load: "", + query: "absent(non_existent_metric)", + queryTime: time.Now(), + sortByLabels: false, + }, } disableOptimizerOpts := []bool{true, false} diff --git a/execution/function/functions.go b/execution/function/functions.go index b4dc75e0..53c69999 100644 --- a/execution/function/functions.go +++ b/execution/function/functions.go @@ -7,8 +7,8 @@ import ( "fmt" "math" "time" - - "github.com/efficientgo/core/errors" + + "github.com/efficientgo/core/errors" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql" @@ -434,6 +434,22 @@ var Funcs = map[string]FunctionCall{ return float64(t.Year()) }) }, + "absent": func(f FunctionArgs) promql.Sample { + if len(f.Points) == 0 { + return promql.Sample{ + Metric: f.Labels, + Point: promql.Point{ + T: f.StepTime, + V: 1, + }, + } + } + + return promql.Sample{ + Metric: f.Labels, + Point: promql.Point{}, + } + }, } func NewFunctionCall(f *parser.Function) (FunctionCall, error) {