mirror of https://github.com/prometheus/prometheus
Add absent() function.
A common problem in Prometheus alerting is to detect when no timeseries exist for a given metric name and label combination. Unfortunately, Prometheus alert expressions need to be of vector type, and "count(nonexistent_metric)" results in an empty vector, yielding no output vector elements to base an alert on. The newly introduced absent() function solves this issue: ALERT FooAbsent IF absent(foo{job="myjob"}) [...] absent() has the following behavior: - if the vector passed to it has any elements, it returns an empty vector. - if the vector passed to it has no elements, it returns a 1-element vector with the value 1. In the second case, absent() tries to be smart about deriving labels of the 1-element output vector from the input vector: absent(nonexistent{job="myjob"}) => {job="myjob"} absent(nonexistent{job="myjob",instance=~".*"}) => {job="myjob"} absent(sum(nonexistent{job="myjob"})) => {} That is, if the passed vector is a literal vector selector, it takes all "=" label matchers as the basis for the output labels, but ignores all non-equals or regex matchers. Also, if the passed vector results from a non-selector expression, no labels can be derived. Change-Id: I948505a1488d50265ab5692a3286bd7c8c70cd78pull/413/head
parent
3d47f94149
commit
b7bf11230a
|
@ -454,6 +454,29 @@ func absImpl(timestamp clientmodel.Timestamp, args []Node) interface{} {
|
||||||
return vector
|
return vector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === absent(vector VectorNode) Vector ===
|
||||||
|
func absentImpl(timestamp clientmodel.Timestamp, args []Node) interface{} {
|
||||||
|
n := args[0].(VectorNode)
|
||||||
|
if len(n.Eval(timestamp)) > 0 {
|
||||||
|
return Vector{}
|
||||||
|
}
|
||||||
|
m := clientmodel.Metric{}
|
||||||
|
if vs, ok := n.(*VectorSelector); ok {
|
||||||
|
for _, matcher := range vs.labelMatchers {
|
||||||
|
if matcher.Type == metric.Equal && matcher.Name != clientmodel.MetricNameLabel {
|
||||||
|
m[matcher.Name] = matcher.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Vector{
|
||||||
|
&clientmodel.Sample{
|
||||||
|
Metric: m,
|
||||||
|
Value: 1,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var functions = map[string]*Function{
|
var functions = map[string]*Function{
|
||||||
"abs": {
|
"abs": {
|
||||||
name: "abs",
|
name: "abs",
|
||||||
|
@ -461,6 +484,12 @@ var functions = map[string]*Function{
|
||||||
returnType: VECTOR,
|
returnType: VECTOR,
|
||||||
callFn: absImpl,
|
callFn: absImpl,
|
||||||
},
|
},
|
||||||
|
"absent": {
|
||||||
|
name: "absent",
|
||||||
|
argTypes: []ExprType{VECTOR},
|
||||||
|
returnType: VECTOR,
|
||||||
|
callFn: absentImpl,
|
||||||
|
},
|
||||||
"avg_over_time": {
|
"avg_over_time": {
|
||||||
name: "avg_over_time",
|
name: "avg_over_time",
|
||||||
argTypes: []ExprType{MATRIX},
|
argTypes: []ExprType{MATRIX},
|
||||||
|
|
|
@ -596,6 +596,46 @@ func TestExpressions(t *testing.T) {
|
||||||
fullRanges: 0,
|
fullRanges: 0,
|
||||||
intervalRanges: 4,
|
intervalRanges: 4,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
expr: `absent(nonexistent)`,
|
||||||
|
output: []string{
|
||||||
|
`{} => 1 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: `absent(nonexistent{job="testjob", instance="testinstance", method=~".*"})`,
|
||||||
|
output: []string{
|
||||||
|
`{instance="testinstance", job="testjob"} => 1 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: `count_scalar(absent(http_requests))`,
|
||||||
|
output: []string{
|
||||||
|
`scalar: 0 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: `count_scalar(absent(sum(http_requests)))`,
|
||||||
|
output: []string{
|
||||||
|
`scalar: 0 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expr: `absent(sum(nonexistent{job="testjob", instance="testinstance"}))`,
|
||||||
|
output: []string{
|
||||||
|
`{} => 1 @[%v]`,
|
||||||
|
},
|
||||||
|
fullRanges: 0,
|
||||||
|
intervalRanges: 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
storage, closer := newTestStorage(t)
|
storage, closer := newTestStorage(t)
|
||||||
|
|
Loading…
Reference in New Issue