From 2e59249242a44eeccfc80eda88baccd58aaf9d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Henning?= <soeren.henning@jku.at> Date: Sun, 12 Nov 2023 16:05:11 +0100 Subject: [PATCH] Add "first" and "last" aggregation for generic SLO --- docs/creating-a-benchmark.md | 2 +- slo-checker/generic/app/main.py | 10 ++++++++++ slo-checker/generic/app/test.py | 10 ++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/creating-a-benchmark.md b/docs/creating-a-benchmark.md index bbd3eb372..d9e1b779f 100644 --- a/docs/creating-a-benchmark.md +++ b/docs/creating-a-benchmark.md @@ -193,7 +193,7 @@ A good choice to get started is defining an SLO of type `generic`: ``` All you have to do is to define a [PromQL query](https://prometheus.io/docs/prometheus/latest/querying/basics/) describing which metrics should be requested (`promQLQuery`) and how the resulting time series should be evaluated. With `queryAggregation` you specify how the resulting time series is aggregated to a single value and `repetitionAggregation` describes how the results of multiple repetitions are aggregated. Possible values are -`mean`, `median`, `mode`, `sum`, `count`, `max`, `min`, `std`, `var`, `skew`, `kurt` as well as percentiles such as `p99` or `p99.9`. The result of aggregation all repetitions is checked against `threshold`. This check is performed using an `operator`, which describes that the result must be "less than" (`lt`), "less than equal" (`lte`), "greater than" (`gt`) or "greater than equal" (`gte`) to the threshold. +`mean`, `median`, `mode`, `sum`, `count`, `max`, `min`, `std`, `var`, `skew`, `kurt`, `first`, `last` as well as percentiles such as `p99` or `p99.9`. The result of aggregation all repetitions is checked against `threshold`. This check is performed using an `operator`, which describes that the result must be "less than" (`lt`), "less than equal" (`lte`), "greater than" (`gt`) or "greater than equal" (`gte`) to the threshold. If you do not want to have a static threshold, you can also define it relatively to the tested load with `thresholdRelToLoad` or relatively to the tested resource value with `thresholdRelToResources`. For example, setting `thresholdRelToLoad: 0.01` means that in each experiment, the threshold is 1% of the generated load. Even more complex thresholds can be defined with `thresholdFromExpression`. This field accepts a mathematical expression with two variables `L` and `R` for the load and resources, respectively. The previous example with a threshold of 1% of the generated load can thus also be defined with `thresholdFromExpression: 0.01*L`. For further details of allowed expressions, see the documentation of the underlying [exp4j](https://github.com/fasseg/exp4j) library. diff --git a/slo-checker/generic/app/main.py b/slo-checker/generic/app/main.py index 6dd78ac13..ff9de19b5 100644 --- a/slo-checker/generic/app/main.py +++ b/slo-checker/generic/app/main.py @@ -25,6 +25,16 @@ elif os.getenv('LOG_LEVEL') == 'DEBUG': def get_aggr_func(func_string: str): if func_string in ['mean', 'median', 'mode', 'sum', 'count', 'max', 'min', 'std', 'var', 'skew', 'kurt']: return func_string + elif func_string == 'first': + def first(x): + return x.iloc[0] + first.__name__ = 'first' + return first + elif func_string == 'last': + def last(x): + return x.iloc[-1] + last.__name__ = 'last' + return last elif re.search(r'^p\d\d?(\.\d+)?$', func_string): # matches strings like 'p99', 'p99.99', 'p1', 'p0.001' def percentile(x): return x.quantile(float(func_string[1:]) / 100) diff --git a/slo-checker/generic/app/test.py b/slo-checker/generic/app/test.py index 2609225dd..8405335f4 100644 --- a/slo-checker/generic/app/test.py +++ b/slo-checker/generic/app/test.py @@ -30,11 +30,17 @@ class TestSloEvaluation(unittest.TestCase): def test_get_aggr_func_p99_(self): self.assertRaises(ValueError, get_aggr_func, 'p99.') - def test_get_aggr_func_p99_(self): + def test_get_aggr_func_q99(self): self.assertRaises(ValueError, get_aggr_func, 'q99') - def test_get_aggr_func_p99_(self): + def test_get_aggr_func_mux(self): self.assertRaises(ValueError, get_aggr_func, 'mux') + + def test_get_aggr_func_first(self): + self.assertTrue(callable(get_aggr_func('first'))) + + def test_get_aggr_func_last(self): + self.assertTrue(callable(get_aggr_func('last'))) def test_check_result_lt(self): self.assertEqual(check_result(100, 'lt', 200), True) -- GitLab