diff --git a/cloudkitty/collector/prometheus.py b/cloudkitty/collector/prometheus.py index e9d1db88..ee12b533 100644 --- a/cloudkitty/collector/prometheus.py +++ b/cloudkitty/collector/prometheus.py @@ -19,6 +19,7 @@ from decimal import ROUND_HALF_UP from oslo_config import cfg from oslo_log import log from voluptuous import In +from voluptuous import Optional from voluptuous import Required from voluptuous import Schema @@ -71,6 +72,12 @@ PROMETHEUS_EXTRA_SCHEMA = { 'min', 'stddev', 'stdvar', 'sum' ]), + Optional('query_function'): + In([ + 'abs', 'ceil', 'exp', + 'floor', 'ln', 'log2', + 'log10', 'round', 'sqrt' + ]) } } @@ -139,18 +146,40 @@ class PrometheusCollector(collector.BaseCollector): """Returns metrics to be valorized.""" scope_key = CONF.collect.scope_key method = self.conf[metric_name]['extra_args']['aggregation_method'] + query_function = self.conf[metric_name]['extra_args'].get( + 'query_function') groupby = self.conf[metric_name].get('groupby', []) metadata = self.conf[metric_name].get('metadata', []) period = tzutils.diff_seconds(end, start) time = end - query = '{0}({0}_over_time({1}{{{2}="{3}"}}[{4}s])) by ({5})'.format( - method, + # The metric with the period + query = '{0}{{{1}="{2}"}}[{3}s]'.format( metric_name, scope_key, scope_id, - period, - ', '.join(groupby + metadata), + period + ) + # Applying the aggregation_method on a Range Vector + query = "{0}_over_time({1})".format( + method, + query + ) + # Applying the query_function + if query_function is not None: + query = "{0}({1})".format( + query_function, + query + ) + # Applying the aggregation_method on a Instant Vector + query = "{0}({1})".format( + method, + query + ) + # Filter by groupby and metadata + query = "{0} by ({1})".format( + query, + ', '.join(groupby + metadata) ) try: diff --git a/cloudkitty/tests/collectors/test_prometheus.py b/cloudkitty/tests/collectors/test_prometheus.py index 07c0ce9b..ddc03047 100644 --- a/cloudkitty/tests/collectors/test_prometheus.py +++ b/cloudkitty/tests/collectors/test_prometheus.py @@ -47,6 +47,7 @@ class PrometheusCollectorTest(tests.TestCase): ], 'extra_args': { 'aggregation_method': 'avg', + 'query_function': 'abs' }, }, } @@ -56,9 +57,9 @@ class PrometheusCollectorTest(tests.TestCase): def test_fetch_all_build_query(self): query = ( - 'avg(avg_over_time(http_requests_total' + 'avg(abs(avg_over_time(http_requests_total' '{project_id="f266f30b11f246b589fd266f85eeec39"}[3600s]' - ')) by (foo, bar, project_id, code, instance)' + '))) by (foo, bar, project_id, code, instance)' ) with mock.patch.object( diff --git a/cloudkitty/tests/collectors/test_validation.py b/cloudkitty/tests/collectors/test_validation.py index 7b2cc5d6..5e0a235f 100644 --- a/cloudkitty/tests/collectors/test_validation.py +++ b/cloudkitty/tests/collectors/test_validation.py @@ -156,11 +156,13 @@ class MetricConfigValidationTest(tests.TestCase): data = copy.deepcopy(self.base_data) data['metrics']['metric_one']['extra_args'] = { 'aggregation_method': 'max', + 'query_function': 'abs', } expected_output = copy.deepcopy(self.base_output) expected_output['metric_one']['groupby'].append('project_id') expected_output['metric_one']['extra_args'] = { 'aggregation_method': 'max', + 'query_function': 'abs', } self.assertEqual( diff --git a/doc/source/admin/configuration/collector.rst b/doc/source/admin/configuration/collector.rst index b689f945..25b65c30 100644 --- a/doc/source/admin/configuration/collector.rst +++ b/doc/source/admin/configuration/collector.rst @@ -302,3 +302,11 @@ Prometheus * ``aggregation_method``: Defaults to ``max``. The aggregation method to use when retrieving measures from prometheus. Must be one of ``avg``, ``min``, ``max``, ``sum``, ``count``, ``stddev``, ``stdvar``. + +* ``query_function``: Optional argument. The function to apply to an instant + vector after the ``aggregation_method`` or ``range_function`` has altered the + data. Must be one of ``abs``, ``ceil``, ``exp``, ``floor``, ``ln``, ``log2``, + ``log10``, ``round``, ``sqrt``. For more information on these functions, + you can check `this page`_ + +.. _this page: https://prometheus.io/docs/prometheus/latest/querying/basics/