From 7c85001a565a0122043e4ee7e7ab1a845be29067 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Fri, 19 Oct 2018 14:24:49 -0700 Subject: [PATCH 1/3] Add helper class for stats/metrics conversion --- opencensus/stats/metric_utils.py | 82 +++++++++++++++++++++ tests/unit/stats/test_metric_utils.py | 102 ++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 opencensus/stats/metric_utils.py create mode 100644 tests/unit/stats/test_metric_utils.py diff --git a/opencensus/stats/metric_utils.py b/opencensus/stats/metric_utils.py new file mode 100644 index 000000000..4b38a9639 --- /dev/null +++ b/opencensus/stats/metric_utils.py @@ -0,0 +1,82 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Utilities to convert stats data models to metrics data models. +""" + +from opencensus.metrics import label_key +from opencensus.metrics.export import metric_descriptor +from opencensus.stats import aggregation as aggregation_module +from opencensus.stats import measure as measure_module + +# To check that an aggregation's reported type matches its class +AGGREGATION_TYPE_MAP = { + aggregation_module.Type.SUM: + aggregation_module.SumAggregation, + aggregation_module.Type.COUNT: + aggregation_module.CountAggregation, + aggregation_module.Type.DISTRIBUTION: + aggregation_module.DistributionAggregation, + aggregation_module.Type.LASTVALUE: + aggregation_module.LastValueAggregation, +} + + +def get_metric_type(measure, aggregation): + """Get the corresponding metric type for the given stats type. + + :type measure: (:class: '~opencensus.stats.measure.BaseMeasure') + :param measure: the measure for which to find a metric type + + :type aggregation: (:class: + '~opencensus.stats.aggregation.BaseAggregation') + :param aggregation: the aggregation for which to find a metric type + """ + if aggregation.aggregation_type == aggregation_module.Type.NONE: + raise ValueError("aggregation type must not be NONE") + assert isinstance(aggregation, + AGGREGATION_TYPE_MAP[aggregation.aggregation_type]) + + if aggregation.aggregation_type == aggregation_module.Type.SUM: + if isinstance(measure, measure_module.MeasureInt): + return metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64 + elif isinstance(measure, measure_module.MeasureFloat): + return metric_descriptor.MetricDescriptorType.CUMULATIVE_DOUBLE + else: + raise ValueError + elif aggregation.aggregation_type == aggregation_module.Type.COUNT: + return metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64 + elif aggregation.aggregation_type == aggregation_module.Type.DISTRIBUTION: + return metric_descriptor.MetricDescriptorType.CUMULATIVE_DISTRIBUTION + elif aggregation.aggregation_type == aggregation_module.Type.LASTVALUE: + if isinstance(measure, measure_module.MeasureInt): + return metric_descriptor.MetricDescriptorType.GAUGE_INT64 + elif isinstance(measure, measure_module.MeasureFloat): + return metric_descriptor.MetricDescriptorType.GAUGE_DOUBLE + else: + raise ValueError + else: + raise AssertionError # pragma: NO COVER + + +def get_metric_descriptor(view): + """Get a MetricDescriptor for given view data. + + :type view: (:class: '~opencensus.stats.view.View') + :param view: the view data to for which to build a metric descriptor + """ + return metric_descriptor.MetricDescriptor( + view.name, view.description, view.measure.unit, + get_metric_type(view.measure, view.aggregation), + [label_key.LabelKey(tk, "") for tk in view.columns]) diff --git a/tests/unit/stats/test_metric_utils.py b/tests/unit/stats/test_metric_utils.py new file mode 100644 index 000000000..7a06030f7 --- /dev/null +++ b/tests/unit/stats/test_metric_utils.py @@ -0,0 +1,102 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import mock +except ImportError: + from unittest import mock + +import unittest + +from opencensus.metrics.export import metric_descriptor +from opencensus.stats import aggregation +from opencensus.stats import measure +from opencensus.stats import metric_utils +from opencensus.stats import view + + +class TestMetricUtils(unittest.TestCase): + def test_get_metric_type(self): + measure_int = mock.Mock(spec=measure.MeasureInt) + measure_float = mock.Mock(spec=measure.MeasureFloat) + agg_sum = mock.Mock(spec=aggregation.SumAggregation) + agg_sum.aggregation_type = aggregation.Type.SUM + agg_count = mock.Mock(spec=aggregation.CountAggregation) + agg_count.aggregation_type = aggregation.Type.COUNT + agg_dist = mock.Mock(spec=aggregation.DistributionAggregation) + agg_dist.aggregation_type = aggregation.Type.DISTRIBUTION + agg_lv = mock.Mock(spec=aggregation.LastValueAggregation) + agg_lv.aggregation_type = aggregation.Type.LASTVALUE + + view_to_metric_type = { + (measure_int, agg_sum): + metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64, + (measure_int, agg_count): + metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64, + (measure_int, agg_dist): + metric_descriptor.MetricDescriptorType.CUMULATIVE_DISTRIBUTION, + (measure_int, agg_lv): + metric_descriptor.MetricDescriptorType.GAUGE_INT64, + (measure_float, agg_sum): + metric_descriptor.MetricDescriptorType.CUMULATIVE_DOUBLE, + (measure_float, agg_count): + metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64, + (measure_float, agg_dist): + metric_descriptor.MetricDescriptorType.CUMULATIVE_DISTRIBUTION, + (measure_float, agg_lv): + metric_descriptor.MetricDescriptorType.GAUGE_DOUBLE, + } + + for (mm, ma), metric_type in view_to_metric_type.items(): + self.assertEqual(metric_utils.get_metric_type(mm, ma), metric_type) + + def test_get_metric_type_bad_aggregation(self): + base_agg = mock.Mock(spec=aggregation.BaseAggregation) + base_agg.aggregation_type = aggregation.Type.NONE + with self.assertRaises(ValueError): + metric_utils.get_metric_type(mock.Mock(), base_agg) + + bad_agg = mock.Mock(spec=aggregation.SumAggregation) + bad_agg.aggregation_type = aggregation.Type.COUNT + with self.assertRaises(AssertionError): + metric_utils.get_metric_type(mock.Mock(), bad_agg) + + def test_get_metric_type_bad_measure(self): + base_measure = mock.Mock(spec=measure.BaseMeasure) + agg_sum = mock.Mock(spec=aggregation.SumAggregation) + agg_sum.aggregation_type = aggregation.Type.SUM + agg_lv = mock.Mock(spec=aggregation.LastValueAggregation) + agg_lv.aggregation_type = aggregation.Type.LASTVALUE + with self.assertRaises(ValueError): + metric_utils.get_metric_type(base_measure, agg_sum) + with self.assertRaises(ValueError): + metric_utils.get_metric_type(base_measure, agg_lv) + + def test_get_metric_descriptor(self): + mock_measure = mock.Mock(spec=measure.MeasureFloat) + mock_agg = mock.Mock(spec=aggregation.SumAggregation) + mock_agg.aggregation_type = aggregation.Type.SUM + test_view = view.View("name", "description", ["tk1", "tk2"], + mock_measure, mock_agg) + + md = metric_utils.get_metric_descriptor(test_view) + self.assertTrue(isinstance(md, metric_descriptor.MetricDescriptor)) + self.assertEqual(md.name, test_view.name) + self.assertEqual(md.description, test_view.description) + self.assertEqual(md.unit, test_view.measure.unit) + self.assertEqual( + md.type, metric_descriptor.MetricDescriptorType.CUMULATIVE_DOUBLE) + self.assertTrue( + all(lk.key == col + for lk, col in zip(md.label_keys, test_view.columns))) From 19808b1e74b39b65bd699c58f68a97be52fa01fa Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Mon, 22 Oct 2018 10:27:51 -0700 Subject: [PATCH 2/3] s/get_metric_descriptor/view_to_metric_descriptor/ --- opencensus/stats/metric_utils.py | 2 +- tests/unit/stats/test_metric_utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/opencensus/stats/metric_utils.py b/opencensus/stats/metric_utils.py index 4b38a9639..c68d931b0 100644 --- a/opencensus/stats/metric_utils.py +++ b/opencensus/stats/metric_utils.py @@ -70,7 +70,7 @@ def get_metric_type(measure, aggregation): raise AssertionError # pragma: NO COVER -def get_metric_descriptor(view): +def view_to_metric_descriptor(view): """Get a MetricDescriptor for given view data. :type view: (:class: '~opencensus.stats.view.View') diff --git a/tests/unit/stats/test_metric_utils.py b/tests/unit/stats/test_metric_utils.py index 7a06030f7..5247344fb 100644 --- a/tests/unit/stats/test_metric_utils.py +++ b/tests/unit/stats/test_metric_utils.py @@ -83,14 +83,14 @@ def test_get_metric_type_bad_measure(self): with self.assertRaises(ValueError): metric_utils.get_metric_type(base_measure, agg_lv) - def test_get_metric_descriptor(self): + def test_view_to_metric_descriptor(self): mock_measure = mock.Mock(spec=measure.MeasureFloat) mock_agg = mock.Mock(spec=aggregation.SumAggregation) mock_agg.aggregation_type = aggregation.Type.SUM test_view = view.View("name", "description", ["tk1", "tk2"], mock_measure, mock_agg) - md = metric_utils.get_metric_descriptor(test_view) + md = metric_utils.view_to_metric_descriptor(test_view) self.assertTrue(isinstance(md, metric_descriptor.MetricDescriptor)) self.assertEqual(md.name, test_view.name) self.assertEqual(md.description, test_view.description) From 112d89a3c08b46aec37837ec0f57d9a537b1abf8 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Mon, 22 Oct 2018 10:33:52 -0700 Subject: [PATCH 3/3] Add TODO comment re: label key descriptions --- opencensus/stats/metric_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opencensus/stats/metric_utils.py b/opencensus/stats/metric_utils.py index c68d931b0..69f4eb349 100644 --- a/opencensus/stats/metric_utils.py +++ b/opencensus/stats/metric_utils.py @@ -79,4 +79,5 @@ def view_to_metric_descriptor(view): return metric_descriptor.MetricDescriptor( view.name, view.description, view.measure.unit, get_metric_type(view.measure, view.aggregation), + # TODO: add label key description [label_key.LabelKey(tk, "") for tk in view.columns])