mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmselect/promql: add share_le_over_time
and share_gt_over_time
functions for SLI and SLO calculations
This commit is contained in:
parent
0038365206
commit
cb3a342882
5 changed files with 126 additions and 0 deletions
|
@ -3083,6 +3083,28 @@ func TestExecSuccess(t *testing.T) {
|
||||||
resultExpected := []netstorage.Result{r}
|
resultExpected := []netstorage.Result{r}
|
||||||
f(q, resultExpected)
|
f(q, resultExpected)
|
||||||
})
|
})
|
||||||
|
t.Run(`share_gt_over_time`, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
q := `share_gt_over_time(rand(0)[200s:10s], 0.7)`
|
||||||
|
r := netstorage.Result{
|
||||||
|
MetricName: metricNameExpected,
|
||||||
|
Values: []float64{0.35, 0.3, 0.5, 0.3, 0.3, 0.25},
|
||||||
|
Timestamps: timestampsExpected,
|
||||||
|
}
|
||||||
|
resultExpected := []netstorage.Result{r}
|
||||||
|
f(q, resultExpected)
|
||||||
|
})
|
||||||
|
t.Run(`share_le_over_time`, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
q := `share_le_over_time(rand(0)[200s:10s], 0.7)`
|
||||||
|
r := netstorage.Result{
|
||||||
|
MetricName: metricNameExpected,
|
||||||
|
Values: []float64{0.65, 0.7, 0.5, 0.7, 0.7, 0.75},
|
||||||
|
Timestamps: timestampsExpected,
|
||||||
|
}
|
||||||
|
resultExpected := []netstorage.Result{r}
|
||||||
|
f(q, resultExpected)
|
||||||
|
})
|
||||||
t.Run(`increases_over_time`, func(t *testing.T) {
|
t.Run(`increases_over_time`, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
q := `increases_over_time(rand(0)[200s:10s])`
|
q := `increases_over_time(rand(0)[200s:10s])`
|
||||||
|
|
|
@ -49,6 +49,8 @@ var rollupFuncs = map[string]newRollupFunc{
|
||||||
"lifetime": newRollupFuncOneArg(rollupLifetime),
|
"lifetime": newRollupFuncOneArg(rollupLifetime),
|
||||||
"lag": newRollupFuncOneArg(rollupLag),
|
"lag": newRollupFuncOneArg(rollupLag),
|
||||||
"scrape_interval": newRollupFuncOneArg(rollupScrapeInterval),
|
"scrape_interval": newRollupFuncOneArg(rollupScrapeInterval),
|
||||||
|
"share_le_over_time": newRollupShareLE,
|
||||||
|
"share_gt_over_time": newRollupShareGT,
|
||||||
"rollup": newRollupFuncOneArg(rollupFake),
|
"rollup": newRollupFuncOneArg(rollupFake),
|
||||||
"rollup_rate": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
"rollup_rate": newRollupFuncOneArg(rollupFake), // + rollupFuncsRemoveCounterResets
|
||||||
"rollup_deriv": newRollupFuncOneArg(rollupFake),
|
"rollup_deriv": newRollupFuncOneArg(rollupFake),
|
||||||
|
@ -529,6 +531,56 @@ func linearRegression(rfa *rollupFuncArg) (float64, float64) {
|
||||||
return v, k
|
return v, k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRollupShareLE(args []interface{}) (rollupFunc, error) {
|
||||||
|
return newRollupShareFilter(args, countFilterLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func countFilterLE(values []float64, le float64) int {
|
||||||
|
n := 0
|
||||||
|
for _, v := range values {
|
||||||
|
if v <= le {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRollupShareGT(args []interface{}) (rollupFunc, error) {
|
||||||
|
return newRollupShareFilter(args, countFilterGT)
|
||||||
|
}
|
||||||
|
|
||||||
|
func countFilterGT(values []float64, gt float64) int {
|
||||||
|
n := 0
|
||||||
|
for _, v := range values {
|
||||||
|
if v > gt {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRollupShareFilter(args []interface{}, countFilter func(values []float64, limit float64) int) (rollupFunc, error) {
|
||||||
|
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
limits, err := getScalar(args[1], 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rf := func(rfa *rollupFuncArg) float64 {
|
||||||
|
// There is no need in handling NaNs here, since they must be cleaned up
|
||||||
|
// before calling rollup funcs.
|
||||||
|
values := rfa.values
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nan
|
||||||
|
}
|
||||||
|
limit := limits[rfa.idx]
|
||||||
|
n := countFilter(values, limit)
|
||||||
|
return float64(n) / float64(len(values))
|
||||||
|
}
|
||||||
|
return rf, nil
|
||||||
|
}
|
||||||
|
|
||||||
func newRollupQuantile(args []interface{}) (rollupFunc, error) {
|
func newRollupQuantile(args []interface{}) (rollupFunc, error) {
|
||||||
if err := expectRollupArgsNum(args, 2); err != nil {
|
if err := expectRollupArgsNum(args, 2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -192,6 +192,52 @@ func testRollupFunc(t *testing.T, funcName string, args []interface{}, meExpecte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRollupShareLEOverTime(t *testing.T) {
|
||||||
|
f := func(le, vExpected float64) {
|
||||||
|
t.Helper()
|
||||||
|
les := []*timeseries{{
|
||||||
|
Values: []float64{le},
|
||||||
|
Timestamps: []int64{123},
|
||||||
|
}}
|
||||||
|
var me metricsql.MetricExpr
|
||||||
|
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, les}
|
||||||
|
testRollupFunc(t, "share_le_over_time", args, &me, vExpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
f(-123, 0)
|
||||||
|
f(0, 0)
|
||||||
|
f(10, 0)
|
||||||
|
f(12, 0.08333333333333333)
|
||||||
|
f(30, 0.16666666666666666)
|
||||||
|
f(50, 0.75)
|
||||||
|
f(100, 0.9166666666666666)
|
||||||
|
f(123, 1)
|
||||||
|
f(1000, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRollupShareGTOverTime(t *testing.T) {
|
||||||
|
f := func(gt, vExpected float64) {
|
||||||
|
t.Helper()
|
||||||
|
gts := []*timeseries{{
|
||||||
|
Values: []float64{gt},
|
||||||
|
Timestamps: []int64{123},
|
||||||
|
}}
|
||||||
|
var me metricsql.MetricExpr
|
||||||
|
args := []interface{}{&metricsql.RollupExpr{Expr: &me}, gts}
|
||||||
|
testRollupFunc(t, "share_gt_over_time", args, &me, vExpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
f(-123, 1)
|
||||||
|
f(0, 1)
|
||||||
|
f(10, 1)
|
||||||
|
f(12, 0.9166666666666666)
|
||||||
|
f(30, 0.8333333333333334)
|
||||||
|
f(50, 0.25)
|
||||||
|
f(100, 0.08333333333333333)
|
||||||
|
f(123, 0)
|
||||||
|
f(1000, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRollupQuantileOverTime(t *testing.T) {
|
func TestRollupQuantileOverTime(t *testing.T) {
|
||||||
f := func(phi, vExpected float64) {
|
f := func(phi, vExpected float64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
|
@ -89,3 +89,7 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g
|
||||||
- `bottomk_max(k, q)` - returns bottom K time series with the min maximums on the given time range
|
- `bottomk_max(k, q)` - returns bottom K time series with the min maximums on the given time range
|
||||||
- `bottomk_avg(k, q)` - returns bottom K time series with the min averages on the given time range
|
- `bottomk_avg(k, q)` - returns bottom K time series with the min averages on the given time range
|
||||||
- `bottomk_median(k, q)` - returns bottom K time series with the min medians on the given time range
|
- `bottomk_median(k, q)` - returns bottom K time series with the min medians on the given time range
|
||||||
|
- `share_le_over_time(m[d], le)` - returns share (in the range 0..1) of values in `m` over `d`, which are smaller or equal to `le`. Useful for calculating SLI and SLO.
|
||||||
|
Example: `share_le_over_time(memory_usage_bytes[24h], 100*1024*1024)` returns the share of time series values for the last 24 hours when memory usage was below or equal to 100MB.
|
||||||
|
- `share_gt_over_time(m[d], gt)` - returns share (in the range 0..1) of values in `m` over `d`, which are bigger than `gt`. Useful for calculating SLI and SLO.
|
||||||
|
Example: `share_gt_over_time(up[24h], 0)` - returns service availability for the last 24 hours.
|
||||||
|
|
|
@ -41,6 +41,8 @@ var rollupFuncs = map[string]bool{
|
||||||
"lifetime": true,
|
"lifetime": true,
|
||||||
"lag": true,
|
"lag": true,
|
||||||
"scrape_interval": true,
|
"scrape_interval": true,
|
||||||
|
"share_le_over_time": true,
|
||||||
|
"share_gt_over_time": true,
|
||||||
"rollup": true,
|
"rollup": true,
|
||||||
"rollup_rate": true,
|
"rollup_rate": true,
|
||||||
"rollup_deriv": true,
|
"rollup_deriv": true,
|
||||||
|
|
Loading…
Reference in a new issue