diff --git a/docs/examples/basic_meter/basic_metrics.py b/docs/examples/basic_meter/basic_metrics.py index e702be42e22..5d137bf01e4 100644 --- a/docs/examples/basic_meter/basic_metrics.py +++ b/docs/examples/basic_meter/basic_metrics.py @@ -84,21 +84,21 @@ def usage(argv): label_keys=("environment",), ) -# Labelsets are used to identify key-values that are associated with a specific +# Labels are used to identify key-values that are associated with a specific # metric that you want to record. These are useful for pre-aggregation and can # be used to store custom dimensions pertaining to a metric -staging_label_set = meter.get_label_set({"environment": "staging"}) -testing_label_set = meter.get_label_set({"environment": "testing"}) +staging_labels = {"environment": "staging"} +testing_labels = {"environment": "testing"} # Update the metric instruments using the direct calling convention -requests_counter.add(25, staging_label_set) -requests_size.record(100, staging_label_set) +requests_counter.add(25, staging_labels) +requests_size.record(100, staging_labels) time.sleep(5) -requests_counter.add(50, staging_label_set) -requests_size.record(5000, staging_label_set) +requests_counter.add(50, staging_labels) +requests_size.record(5000, staging_labels) time.sleep(5) -requests_counter.add(35, testing_label_set) -requests_size.record(2, testing_label_set) +requests_counter.add(35, testing_labels) +requests_size.record(2, testing_labels) time.sleep(5) diff --git a/docs/examples/basic_meter/calling_conventions.py b/docs/examples/basic_meter/calling_conventions.py index 6efa737e63c..15b57fdafcb 100644 --- a/docs/examples/basic_meter/calling_conventions.py +++ b/docs/examples/basic_meter/calling_conventions.py @@ -56,27 +56,27 @@ label_keys=("environment",), ) -label_set = meter.get_label_set({"environment": "staging"}) +labels = {"environment": "staging"} print("Updating using direct calling convention...") -# You can record metrics directly using the metric instrument. You pass in a -# labelset that you would like to record for. -requests_counter.add(25, label_set) +# You can record metrics directly using the metric instrument. You pass in +# labels that you would like to record for. +requests_counter.add(25, labels) time.sleep(5) print("Updating using a bound instrument...") # You can record metrics with bound metric instruments. Bound metric -# instruments are created by passing in a labelset. A bound metric instrument +# instruments are created by passing in labels. A bound metric instrument # is essentially metric data that corresponds to a specific set of labels. # Therefore, getting a bound metric instrument using the same set of labels # will yield the same bound metric instrument. -bound_requests_counter = requests_counter.bind(label_set) +bound_requests_counter = requests_counter.bind(labels) bound_requests_counter.add(100) time.sleep(5) print("Updating using batch calling convention...") -# You can record metrics in a batch by passing in a labelset and a sequence of +# You can record metrics in a batch by passing in labels and a sequence of # (metric, value) pairs. The value would be recorded for each metric using the -# specified labelset for each. -meter.record_batch(label_set, ((requests_counter, 50), (clicks_counter, 70))) +# specified labels for each. +meter.record_batch(labels, ((requests_counter, 50), (clicks_counter, 70))) time.sleep(5) diff --git a/docs/examples/basic_meter/observer.py b/docs/examples/basic_meter/observer.py index 716968b4aef..0490fbe8efb 100644 --- a/docs/examples/basic_meter/observer.py +++ b/docs/examples/basic_meter/observer.py @@ -19,7 +19,7 @@ import psutil from opentelemetry import metrics -from opentelemetry.sdk.metrics import LabelSet, MeterProvider +from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher from opentelemetry.sdk.metrics.export.controller import PushController @@ -35,8 +35,8 @@ # Callback to gather cpu usage def get_cpu_usage_callback(observer): for (number, percent) in enumerate(psutil.cpu_percent(percpu=True)): - label_set = meter.get_label_set({"cpu_number": str(number)}) - observer.observe(percent, label_set) + labels = {"cpu_number": str(number)} + observer.observe(percent, labels) meter.register_observer( @@ -52,7 +52,7 @@ def get_cpu_usage_callback(observer): # Callback to gather RAM memory usage def get_ram_usage_callback(observer): ram_percent = psutil.virtual_memory().percent - observer.observe(ram_percent, LabelSet()) + observer.observe(ram_percent, {}) meter.register_observer( diff --git a/docs/examples/otcollector-metrics/collector.py b/docs/examples/otcollector-metrics/collector.py index 9bef12603a1..b0420e1bb8c 100644 --- a/docs/examples/otcollector-metrics/collector.py +++ b/docs/examples/otcollector-metrics/collector.py @@ -40,8 +40,8 @@ label_keys=("environment",), ) -staging_label_set = meter.get_label_set({"environment": "staging"}) -requests_counter.add(25, staging_label_set) +staging_labels = {"environment": "staging"} +requests_counter.add(25, staging_labels) print("Metrics are available now at http://localhost:9090/graph") input("Press any key to exit...") diff --git a/docs/examples/prometheus/prometheus.py b/docs/examples/prometheus/prometheus.py index 2561138fb11..cdb60e9ceca 100644 --- a/docs/examples/prometheus/prometheus.py +++ b/docs/examples/prometheus/prometheus.py @@ -41,8 +41,8 @@ label_keys=("environment",), ) -staging_label_set = meter.get_label_set({"environment": "staging"}) -requests_counter.add(25, staging_label_set) +staging_labels = {"environment": "staging"} +requests_counter.add(25, staging_labels) print("Metrics are available now at http://localhost:8000/") input("Press any key to exit...") diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 615d71bd8ad..bbd696015fb 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -249,7 +249,7 @@ The following is an example of emitting metrics to console, in a similar fashion exporter = ConsoleMetricsExporter() controller = PushController(meter, exporter, 5) - staging_label_set = meter.get_label_set({"environment": "staging"}) + staging_labels = {"environment": "staging"} requests_counter = meter.create_metric( name="requests", @@ -260,10 +260,10 @@ The following is an example of emitting metrics to console, in a similar fashion label_keys=("environment",), ) - requests_counter.add(25, staging_label_set) + requests_counter.add(25, staging_labels) time.sleep(5) - requests_counter.add(20, staging_label_set) + requests_counter.add(20, staging_labels) time.sleep(5) @@ -272,8 +272,8 @@ The sleeps will cause the script to take a while, but running it should yield: .. code-block:: sh $ python metrics.py - ConsoleMetricsExporter(data="Counter(name="requests", description="number of requests")", label_set="(('environment', 'staging'),)", value=25) - ConsoleMetricsExporter(data="Counter(name="requests", description="number of requests")", label_set="(('environment', 'staging'),)", value=45) + ConsoleMetricsExporter(data="Counter(name="requests", description="number of requests")", labels="(('environment', 'staging'),)", value=25) + ConsoleMetricsExporter(data="Counter(name="requests", description="number of requests")", labels="(('environment', 'staging'),)", value=45) Using Prometheus ---------------- @@ -331,7 +331,7 @@ And use that instead of the `ConsoleMetricsExporter`: exporter = PrometheusMetricsExporter("MyAppPrefix") controller = PushController(meter, exporter, 5) - staging_label_set = meter.get_label_set({"environment": "staging"}) + staging_labels = {"environment": "staging"} requests_counter = meter.create_metric( name="requests", @@ -342,10 +342,10 @@ And use that instead of the `ConsoleMetricsExporter`: label_keys=("environment",), ) - requests_counter.add(25, staging_label_set) + requests_counter.add(25, staging_labels) time.sleep(5) - requests_counter.add(20, staging_label_set) + requests_counter.add(20, staging_labels) time.sleep(5) # This line is added to keep the HTTP server up long enough to scrape. @@ -463,11 +463,9 @@ And execute the following script: metric_type=Counter, label_keys=("environment",), ) - - # Labelsets are used to identify key-values that are associated with a specific + # Labels are used to identify key-values that are associated with a specific # metric that you want to record. These are useful for pre-aggregation and can # be used to store custom dimensions pertaining to a metric - label_set = meter.get_label_set({"environment": "staging"}) - - requests_counter.add(25, label_set) + labels = {"environment": "staging"} + requests_counter.add(25, labels) time.sleep(10) # give push_controller time to push metrics diff --git a/docs/metrics_example.py b/docs/metrics_example.py index 736b9c7f304..6ab4fd55fba 100644 --- a/docs/metrics_example.py +++ b/docs/metrics_example.py @@ -17,7 +17,7 @@ label_keys=("environment",), ) -staging_label_set = meter.get_label_set({"environment": "staging"}) -requests_counter.add(25, staging_label_set) +staging_labels = {"environment": "staging"} +requests_counter.add(25, staging_labels) input("Press a key to finish...\n") diff --git a/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/__init__.py b/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/__init__.py index e3e5e43cdc3..ae5e2ac33f8 100644 --- a/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/__init__.py +++ b/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/__init__.py @@ -77,10 +77,10 @@ Counter, ("environment",), ) - # Labelsets are used to identify key-values that are associated with a specific + # Labels are used to identify key-values that are associated with a specific # metric that you want to record. These are useful for pre-aggregation and can # be used to store custom dimensions pertaining to a metric - label_set = meter.get_label_set({"environment": "staging"}) + labels = {"environment": "staging"} - counter.add(25, label_set) + counter.add(25, labels) """ diff --git a/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/metrics_exporter/__init__.py b/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/metrics_exporter/__init__.py index 8fcfd813734..5f8424fd00b 100644 --- a/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/metrics_exporter/__init__.py +++ b/ext/opentelemetry-ext-otcollector/src/opentelemetry/ext/otcollector/metrics_exporter/__init__.py @@ -106,7 +106,7 @@ def translate_to_collector( label_values = [] label_keys = [] - for label_tuple in metric_record.label_set.labels: + for label_tuple in metric_record.labels: label_keys.append(metrics_pb2.LabelKey(key=label_tuple[0])) label_values.append( metrics_pb2.LabelValue( @@ -145,11 +145,12 @@ def get_collector_metric_type(metric: Metric) -> metrics_pb2.MetricDescriptor: def get_collector_point(metric_record: MetricRecord) -> metrics_pb2.Point: + # TODO: horrible hack to get original list of keys to then get the bound + # instrument + key = dict(metric_record.labels) point = metrics_pb2.Point( timestamp=utils.proto_timestamp_from_time_ns( - metric_record.metric.bind( - metric_record.label_set - ).last_update_timestamp + metric_record.metric.bind(key).last_update_timestamp ) ) if metric_record.metric.value_type == int: diff --git a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py index 716dac493cf..6133b3bd88b 100644 --- a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py +++ b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py @@ -21,7 +21,12 @@ from opentelemetry import metrics from opentelemetry.ext.otcollector import metrics_exporter -from opentelemetry.sdk.metrics import Counter, Measure, MeterProvider +from opentelemetry.sdk.metrics import ( + Counter, + Measure, + MeterProvider, + get_labels_as_key, +) from opentelemetry.sdk.metrics.export import ( MetricRecord, MetricsExportResult, @@ -36,8 +41,8 @@ def setUpClass(cls): # pylint: disable=protected-access metrics.set_meter_provider(MeterProvider()) cls._meter = metrics.get_meter(__name__) - kvp = {"environment": "staging"} - cls._test_label_set = cls._meter.get_label_set(kvp) + cls._labels = {"environment": "staging"} + cls._key_labels = get_labels_as_key(cls._labels) def test_constructor(self): mock_get_node = mock.Mock() @@ -77,7 +82,6 @@ def test_get_collector_metric_type(self): def test_get_collector_point(self): aggregator = aggregate.CounterAggregator() - label_set = self._meter.get_label_set({"environment": "staging"}) int_counter = self._meter.create_metric( "testName", "testDescription", "unit", int, Counter ) @@ -88,7 +92,7 @@ def test_get_collector_point(self): "testName", "testDescription", "unit", float, Measure ) result = metrics_exporter.get_collector_point( - MetricRecord(aggregator, label_set, int_counter) + MetricRecord(aggregator, self._key_labels, int_counter) ) self.assertIsInstance(result, metrics_pb2.Point) self.assertIsInstance(result.timestamp, Timestamp) @@ -96,13 +100,13 @@ def test_get_collector_point(self): aggregator.update(123.5) aggregator.take_checkpoint() result = metrics_exporter.get_collector_point( - MetricRecord(aggregator, label_set, float_counter) + MetricRecord(aggregator, self._key_labels, float_counter) ) self.assertEqual(result.double_value, 123.5) self.assertRaises( TypeError, metrics_exporter.get_collector_point( - MetricRecord(aggregator, label_set, measure) + MetricRecord(aggregator, self._key_labels, measure) ), ) @@ -118,7 +122,7 @@ def test_export(self): "testname", "testdesc", "unit", int, Counter, ["environment"] ) record = MetricRecord( - aggregate.CounterAggregator(), self._test_label_set, test_metric + aggregate.CounterAggregator(), self._key_labels, test_metric ) result = collector_exporter.export([record]) @@ -137,14 +141,13 @@ def test_export(self): ) def test_translate_to_collector(self): - test_metric = self._meter.create_metric( "testname", "testdesc", "unit", int, Counter, ["environment"] ) aggregator = aggregate.CounterAggregator() aggregator.update(123) aggregator.take_checkpoint() - record = MetricRecord(aggregator, self._test_label_set, test_metric) + record = MetricRecord(aggregator, self._key_labels, test_metric) output_metrics = metrics_exporter.translate_to_collector([record]) self.assertEqual(len(output_metrics), 1) self.assertIsInstance(output_metrics[0], metrics_pb2.Metric) @@ -175,12 +178,12 @@ def test_translate_to_collector(self): self.assertEqual(len(output_metrics[0].timeseries[0].points), 1) self.assertEqual( output_metrics[0].timeseries[0].points[0].timestamp.seconds, - record.metric.bind(record.label_set).last_update_timestamp + record.metric.bind(self._labels).last_update_timestamp // 1000000000, ) self.assertEqual( output_metrics[0].timeseries[0].points[0].timestamp.nanos, - record.metric.bind(record.label_set).last_update_timestamp + record.metric.bind(self._labels).last_update_timestamp % 1000000000, ) self.assertEqual( diff --git a/ext/opentelemetry-ext-prometheus/src/opentelemetry/ext/prometheus/__init__.py b/ext/opentelemetry-ext-prometheus/src/opentelemetry/ext/prometheus/__init__.py index 05d16b552d9..1dd307af938 100644 --- a/ext/opentelemetry-ext-prometheus/src/opentelemetry/ext/prometheus/__init__.py +++ b/ext/opentelemetry-ext-prometheus/src/opentelemetry/ext/prometheus/__init__.py @@ -54,12 +54,12 @@ ("environment",), ) - # Labelsets are used to identify key-values that are associated with a specific + # Labels are used to identify key-values that are associated with a specific # metric that you want to record. These are useful for pre-aggregation and can # be used to store custom dimensions pertaining to a metric - label_set = meter.get_label_set({"environment": "staging"}) + labels = {"environment": "staging"} - counter.add(25, label_set) + counter.add(25, labels) input("Press any key to exit...") API @@ -145,7 +145,7 @@ def _translate_to_prometheus(self, metric_record: MetricRecord): prometheus_metric = None label_values = [] label_keys = [] - for label_tuple in metric_record.label_set.labels: + for label_tuple in metric_record.labels: label_keys.append(self._sanitize(label_tuple[0])) label_values.append(label_tuple[1]) diff --git a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py index 6c2d900c774..f986e0c4f5f 100644 --- a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py +++ b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py @@ -39,8 +39,8 @@ def setUp(self): metrics.Counter, ["environment"], ) - kvp = {"environment": "staging"} - self._test_label_set = self._meter.get_label_set(kvp) + labels = {"environment": "staging"} + self._labels_key = metrics.get_labels_as_key(labels) self._mock_registry_register = mock.Mock() self._registry_register_patch = mock.patch( @@ -67,7 +67,7 @@ def test_shutdown(self): def test_export(self): with self._registry_register_patch: record = MetricRecord( - CounterAggregator(), self._test_label_set, self._test_metric + CounterAggregator(), self._labels_key, self._test_metric ) exporter = PrometheusMetricsExporter() result = exporter.export([record]) @@ -85,12 +85,12 @@ def test_counter_to_prometheus(self): metrics.Counter, ["environment@", "os"], ) - kvp = {"environment@": "staging", "os": "Windows"} - label_set = meter.get_label_set(kvp) + labels = {"environment@": "staging", "os": "Windows"} + key_labels = metrics.get_labels_as_key(labels) aggregator = CounterAggregator() aggregator.update(123) aggregator.take_checkpoint() - record = MetricRecord(aggregator, label_set, metric) + record = MetricRecord(aggregator, key_labels, metric) collector = CustomCollector("testprefix") collector.add_metrics_data([record]) @@ -114,11 +114,11 @@ def test_counter_to_prometheus(self): def test_invalid_metric(self): meter = get_meter_provider().get_meter(__name__) metric = meter.create_metric( - "tesname", "testdesc", "unit", int, TestMetric + "tesname", "testdesc", "unit", int, StubMetric ) - kvp = {"environment": "staging"} - label_set = meter.get_label_set(kvp) - record = MetricRecord(None, label_set, metric) + labels = {"environment": "staging"} + key_labels = metrics.get_labels_as_key(labels) + record = MetricRecord(None, key_labels, metric) collector = CustomCollector("testprefix") collector.add_metrics_data([record]) collector.collect() @@ -135,7 +135,7 @@ def test_sanitize(self): self.assertEqual(collector._sanitize("aAbBcC_12_oi"), "aAbBcC_12_oi") -class TestMetric(metrics.Metric): +class StubMetric(metrics.Metric): def __init__( self, name: str, diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index a3a1c340c89..c0ab525b7d5 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -82,25 +82,6 @@ def record(self, value: ValueT) -> None: """ -class LabelSet(abc.ABC): - """A canonicalized set of labels useful for preaggregation - - Re-usable LabelSet objects provide a potential optimization for scenarios - where bound metric instruments might not be effective. For example, if the - LabelSet will be re-used but only used once per metrics, bound metric - instruments do not offer any optimization. It may best to pre-compute a - canonicalized LabelSet once and re-use it with the direct calling - convention. LabelSets are immutable and should be opaque in implementation. - """ - - -class DefaultLabelSet(LabelSet): - """The default LabelSet. - - Used when no LabelSet implementation is available. - """ - - class Metric(abc.ABC): """Base class for various types of metrics. @@ -109,7 +90,7 @@ class Metric(abc.ABC): """ @abc.abstractmethod - def bind(self, label_set: LabelSet) -> "object": + def bind(self, labels: Dict[str, str]) -> "object": """Gets a bound metric instrument. Bound metric instruments are useful to reduce the cost of repeatedly @@ -121,51 +102,51 @@ def bind(self, label_set: LabelSet) -> "object": provided are permitted. Args: - label_set: `LabelSet` to associate with the bound instrument. + labels: Labels to associate with the bound instrument. """ class DefaultMetric(Metric): """The default Metric used when no Metric implementation is available.""" - def bind(self, label_set: LabelSet) -> "DefaultBoundInstrument": + def bind(self, labels: Dict[str, str]) -> "DefaultBoundInstrument": """Gets a `DefaultBoundInstrument`. Args: - label_set: `LabelSet` to associate with the bound instrument. + labels: Labels to associate with the bound instrument. """ return DefaultBoundInstrument() - def add(self, value: ValueT, label_set: LabelSet) -> None: + def add(self, value: ValueT, labels: Dict[str, str]) -> None: """No-op implementation of `Counter` add. Args: value: The value to add to the counter metric. - label_set: `LabelSet` to associate with the bound instrument. + labels: Labels to associate with the bound instrument. """ - def record(self, value: ValueT, label_set: LabelSet) -> None: + def record(self, value: ValueT, labels: Dict[str, str]) -> None: """No-op implementation of `Measure` record. Args: value: The value to record to this measure metric. - label_set: `LabelSet` to associate with the bound instrument. + labels: Labels to associate with the bound instrument. """ class Counter(Metric): """A counter type metric that expresses the computation of a sum.""" - def bind(self, label_set: LabelSet) -> "BoundCounter": + def bind(self, labels: Dict[str, str]) -> "BoundCounter": """Gets a `BoundCounter`.""" return BoundCounter() - def add(self, value: ValueT, label_set: LabelSet) -> None: + def add(self, value: ValueT, labels: Dict[str, str]) -> None: """Increases the value of the counter by ``value``. Args: value: The value to add to the counter metric. - label_set: `LabelSet` to associate with the returned bound counter. + labels: Labels to associate with the bound instrument. """ @@ -175,16 +156,16 @@ class Measure(Metric): Measure metrics represent raw statistics that are recorded. """ - def bind(self, label_set: LabelSet) -> "BoundMeasure": + def bind(self, labels: Dict[str, str]) -> "BoundMeasure": """Gets a `BoundMeasure`.""" return BoundMeasure() - def record(self, value: ValueT, label_set: LabelSet) -> None: + def record(self, value: ValueT, labels: Dict[str, str]) -> None: """Records the ``value`` to the measure. Args: value: The value to record to this measure metric. - label_set: `LabelSet` to associate with the returned bound measure. + labels: Labels to associate with the bound instrument. """ @@ -199,24 +180,24 @@ class Observer(abc.ABC): """ @abc.abstractmethod - def observe(self, value: ValueT, label_set: LabelSet) -> None: + def observe(self, value: ValueT, labels: Dict[str, str]) -> None: """Captures ``value`` to the observer. Args: value: The value to capture to this observer metric. - label_set: `LabelSet` associated to ``value``. + labels: Labels associated to ``value``. """ class DefaultObserver(Observer): """No-op implementation of ``Observer``.""" - def observe(self, value: ValueT, label_set: LabelSet) -> None: + def observe(self, value: ValueT, labels: Dict[str, str]) -> None: """Captures ``value`` to the observer. Args: value: The value to capture to this observer metric. - label_set: `LabelSet` associated to ``value``. + labels: Labels associated to ``value``. """ @@ -286,20 +267,20 @@ class Meter(abc.ABC): @abc.abstractmethod def record_batch( self, - label_set: LabelSet, + labels: Dict[str, str], record_tuples: Sequence[Tuple["Metric", ValueT]], ) -> None: """Atomically records a batch of `Metric` and value pairs. Allows the functionality of acting upon multiple metrics with a single API call. Implementations should find bound metric instruments that - match the key-value pairs in the labelset. + match the key-value pairs in the labels. - Args: label_set: The `LabelSet` associated with all measurements in the - batch. A measurement is a tuple, representing the `Metric` being - recorded and the corresponding value to record. record_tuples: A - sequence of pairs of `Metric` s and the corresponding value to - record for that metric. + Args: + labels: Labels associated with all measurements in the + batch. + record_tuples: A sequence of pairs of `Metric` s and the + corresponding value to record for that metric. """ @abc.abstractmethod @@ -361,23 +342,13 @@ def unregister_observer(self, observer: "Observer") -> None: observer: The observer to unregister. """ - @abc.abstractmethod - def get_label_set(self, labels: Dict[str, str]) -> "LabelSet": - """Gets a `LabelSet` with the given labels. - - Args: - labels: A dictionary representing label key to label value pairs. - - Returns: A `LabelSet` object canonicalized using the given input. - """ - class DefaultMeter(Meter): """The default Meter used when no Meter implementation is available.""" def record_batch( self, - label_set: LabelSet, + labels: Dict[str, str], record_tuples: Sequence[Tuple["Metric", ValueT]], ) -> None: pass @@ -410,10 +381,6 @@ def register_observer( def unregister_observer(self, observer: "Observer") -> None: pass - def get_label_set(self, labels: Dict[str, str]) -> "LabelSet": - # pylint: disable=no-self-use - return DefaultLabelSet() - _METER_PROVIDER = None diff --git a/opentelemetry-api/tests/metrics/test_metrics.py b/opentelemetry-api/tests/metrics/test_metrics.py index f0f6976eb06..3e760d3d98b 100644 --- a/opentelemetry-api/tests/metrics/test_metrics.py +++ b/opentelemetry-api/tests/metrics/test_metrics.py @@ -21,33 +21,28 @@ class TestMetrics(unittest.TestCase): def test_default(self): default = metrics.DefaultMetric() - default_ls = metrics.DefaultLabelSet() - bound_metric_instr = default.bind(default_ls) + bound_metric_instr = default.bind({}) self.assertIsInstance( bound_metric_instr, metrics.DefaultBoundInstrument ) def test_counter(self): counter = metrics.Counter() - label_set = metrics.LabelSet() - bound_counter = counter.bind(label_set) + bound_counter = counter.bind({}) self.assertIsInstance(bound_counter, metrics.BoundCounter) def test_counter_add(self): counter = metrics.Counter() - label_set = metrics.LabelSet() - counter.add(1, label_set) + counter.add(1, {}) def test_measure(self): measure = metrics.Measure() - label_set = metrics.LabelSet() - bound_measure = measure.bind(label_set) + bound_measure = measure.bind({}) self.assertIsInstance(bound_measure, metrics.BoundMeasure) def test_measure_record(self): measure = metrics.Measure() - label_set = metrics.LabelSet() - measure.record(1, label_set) + measure.record(1, {}) def test_default_bound_metric(self): bound_instrument = metrics.DefaultBoundInstrument() @@ -63,5 +58,4 @@ def test_bound_measure(self): def test_observer(self): observer = metrics.DefaultObserver() - label_set = metrics.LabelSet() - observer.observe(1, label_set) + observer.observe(1, {}) diff --git a/opentelemetry-api/tests/test_implementation.py b/opentelemetry-api/tests/test_implementation.py index ea1e929eefb..735ac4a683f 100644 --- a/opentelemetry-api/tests/test_implementation.py +++ b/opentelemetry-api/tests/test_implementation.py @@ -73,8 +73,7 @@ def test_default_meter(self): def test_record_batch(self): meter = metrics.DefaultMeter() counter = metrics.Counter() - label_set = metrics.LabelSet() - meter.record_batch(label_set, ((counter, 1),)) + meter.record_batch({}, ((counter, 1),)) def test_create_metric(self): meter = metrics.DefaultMeter() @@ -91,8 +90,3 @@ def test_unregister_observer(self): meter = metrics.DefaultMeter() observer = metrics.DefaultObserver() meter.unregister_observer(observer) - - def test_get_label_set(self): - meter = metrics.DefaultMeter() - label_set = meter.get_label_set({}) - self.assertIsInstance(label_set, metrics.DefaultLabelSet) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py index 05d88fc7648..e6f264494d9 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py @@ -26,26 +26,9 @@ logger = logging.getLogger(__name__) -# pylint: disable=redefined-outer-name -class LabelSet(metrics_api.LabelSet): - """See `opentelemetry.metrics.LabelSet`.""" - - def __init__(self, labels: Dict[str, str] = None): - if labels is None: - labels = {} - # LabelSet properties used only in dictionaries for fast lookup - self._labels = tuple(labels.items()) - self._encoded = tuple(sorted(labels.items())) - - @property - def labels(self): - return self._labels - - def __hash__(self): - return hash(self._encoded) - - def __eq__(self, other): - return self._encoded == other._encoded +def get_labels_as_key(labels: Dict[str, str]) -> Tuple[Tuple[str, str]]: + """Gets a list of labels that can be used as a key in a dictionary.""" + return tuple(sorted(labels.items())) class BaseBoundInstrument: @@ -157,10 +140,11 @@ def __init__( self.bound_instruments = {} self.bound_instruments_lock = threading.Lock() - def bind(self, label_set: LabelSet) -> BaseBoundInstrument: + def bind(self, labels: Dict[str, str]) -> BaseBoundInstrument: """See `opentelemetry.metrics.Metric.bind`.""" + key = get_labels_as_key(labels) with self.bound_instruments_lock: - bound_instrument = self.bound_instruments.get(label_set) + bound_instrument = self.bound_instruments.get(key) if bound_instrument is None: bound_instrument = self.BOUND_INSTR_TYPE( self.value_type, @@ -168,7 +152,7 @@ def bind(self, label_set: LabelSet) -> BaseBoundInstrument: # Aggregator will be created based off type of metric self.meter.batcher.aggregator_for(self.__class__), ) - self.bound_instruments[label_set] = bound_instrument + self.bound_instruments[key] = bound_instrument bound_instrument.increase_ref_count() return bound_instrument @@ -186,9 +170,9 @@ class Counter(Metric, metrics_api.Counter): BOUND_INSTR_TYPE = BoundCounter - def add(self, value: metrics_api.ValueT, label_set: LabelSet) -> None: + def add(self, value: metrics_api.ValueT, labels: Dict[str, str]) -> None: """See `opentelemetry.metrics.Counter.add`.""" - bound_intrument = self.bind(label_set) + bound_intrument = self.bind(labels) bound_intrument.add(value) bound_intrument.release() @@ -200,9 +184,11 @@ class Measure(Metric, metrics_api.Measure): BOUND_INSTR_TYPE = BoundMeasure - def record(self, value: metrics_api.ValueT, label_set: LabelSet) -> None: + def record( + self, value: metrics_api.ValueT, labels: Dict[str, str] + ) -> None: """See `opentelemetry.metrics.Measure.record`.""" - bound_intrument = self.bind(label_set) + bound_intrument = self.bind(labels) bound_intrument.record(value) bound_intrument.release() @@ -234,7 +220,9 @@ def __init__( self.aggregators = {} - def observe(self, value: metrics_api.ValueT, label_set: LabelSet) -> None: + def observe( + self, value: metrics_api.ValueT, labels: Dict[str, str] + ) -> None: if not self.enabled: return if not isinstance(value, self.value_type): @@ -243,12 +231,13 @@ def observe(self, value: metrics_api.ValueT, label_set: LabelSet) -> None: ) return - if label_set not in self.aggregators: + key = get_labels_as_key(labels) + if key not in self.aggregators: # TODO: how to cleanup aggregators? - self.aggregators[label_set] = self.meter.batcher.aggregator_for( + self.aggregators[key] = self.meter.batcher.aggregator_for( self.__class__ ) - aggregator = self.aggregators[label_set] + aggregator = self.aggregators[key] aggregator.update(value) def run(self) -> bool: @@ -274,18 +263,14 @@ class Record: def __init__( self, metric: metrics_api.MetricT, - label_set: LabelSet, + labels: Dict[str, str], aggregator: Aggregator, ): self.metric = metric - self.label_set = label_set + self.labels = labels self.aggregator = aggregator -# Used when getting a LabelSet with no key/values -EMPTY_LABEL_SET = LabelSet() - - class Meter(metrics_api.Meter): """See `opentelemetry.metrics.Meter`. @@ -326,19 +311,19 @@ def _collect_metrics(self) -> None: to_remove = [] with metric.bound_instruments_lock: - for label_set, bound_instr in metric.bound_instruments.items(): + for labels, bound_instr in metric.bound_instruments.items(): # TODO: Consider storing records in memory? - record = Record(metric, label_set, bound_instr.aggregator) + record = Record(metric, labels, bound_instr.aggregator) # Checkpoints the current aggregators # Applies different batching logic based on type of batcher self.batcher.process(record) if bound_instr.ref_count() == 0: - to_remove.append(label_set) + to_remove.append(labels) # Remove handles that were released - for label_set in to_remove: - del metric.bound_instruments[label_set] + for labels in to_remove: + del metric.bound_instruments[labels] def _collect_observers(self) -> None: with self.observers_lock: @@ -350,18 +335,20 @@ def _collect_observers(self) -> None: if not observer.run(): continue - for label_set, aggregator in observer.aggregators.items(): - record = Record(observer, label_set, aggregator) + for labels, aggregator in observer.aggregators.items(): + record = Record(observer, labels, aggregator) self.batcher.process(record) def record_batch( self, - label_set: LabelSet, + labels: Dict[str, str], record_tuples: Sequence[Tuple[metrics_api.Metric, metrics_api.ValueT]], ) -> None: """See `opentelemetry.metrics.Meter.record_batch`.""" + # TODO: Avoid enconding the labels for each instrument, encode once + # and reuse. for metric, value in record_tuples: - metric.UPDATE_FUNCTION(value, label_set) + metric.UPDATE_FUNCTION(value, labels) def create_metric( self, @@ -415,18 +402,6 @@ def unregister_observer(self, observer: "Observer") -> None: with self.observers_lock: self.observers.remove(observer) - def get_label_set(self, labels: Dict[str, str]): - """See `opentelemetry.metrics.Meter.create_metric`. - - This implementation encodes the labels to use as a map key. - - Args: - labels: The dictionary of label keys to label values. - """ - if len(labels) == 0: - return EMPTY_LABEL_SET - return LabelSet(labels=labels) - class MeterProvider(metrics_api.MeterProvider): def __init__( diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/__init__.py index a2513b1bfba..8b0fbdb1a37 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/__init__.py @@ -15,6 +15,9 @@ from enum import Enum from typing import Sequence, Tuple +from opentelemetry import metrics as metrics_api +from opentelemetry.sdk.metrics.export.aggregate import Aggregator + class MetricsExportResult(Enum): SUCCESS = 0 @@ -23,9 +26,14 @@ class MetricsExportResult(Enum): class MetricRecord: - def __init__(self, aggregator, label_set, metric): + def __init__( + self, + aggregator: Aggregator, + labels: Tuple[Tuple[str, str]], + metric: metrics_api.MetricT, + ): self.aggregator = aggregator - self.label_set = label_set + self.labels = labels self.metric = metric @@ -43,7 +51,7 @@ def export( Args: metric_records: A sequence of `MetricRecord` s. A `MetricRecord` - contains the metric to be exported, the label set associated + contains the metric to be exported, the labels associated with that metric, as well as the aggregator used to export the current checkpointed value. @@ -70,10 +78,10 @@ def export( ) -> "MetricsExportResult": for record in metric_records: print( - '{}(data="{}", label_set="{}", value={})'.format( + '{}(data="{}", labels="{}", value={})'.format( type(self).__name__, record.metric, - record.label_set.labels, + record.labels, record.aggregator.checkpoint, ) ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/batcher.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/batcher.py index a2a3ec48d38..7b599f4c7da 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/batcher.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/batcher.py @@ -63,8 +63,8 @@ def checkpoint_set(self) -> Sequence[MetricRecord]: data in all of the aggregators in this batcher. """ metric_records = [] - for (metric, label_set), aggregator in self._batch_map.items(): - metric_records.append(MetricRecord(aggregator, label_set, metric)) + for (metric, labels), aggregator in self._batch_map.items(): + metric_records.append(MetricRecord(aggregator, labels, metric)) return metric_records def finished_collection(self): @@ -90,7 +90,7 @@ class UngroupedBatcher(Batcher): def process(self, record): # Checkpoints the current aggregator value to be collected for export record.aggregator.take_checkpoint() - batch_key = (record.metric, record.label_set) + batch_key = (record.metric, record.labels) batch_value = self._batch_map.get(batch_key) aggregator = record.aggregator if batch_value: diff --git a/opentelemetry-sdk/tests/metrics/export/test_export.py b/opentelemetry-sdk/tests/metrics/export/test_export.py index 5e0a8e46fb8..311237505ce 100644 --- a/opentelemetry-sdk/tests/metrics/export/test_export.py +++ b/opentelemetry-sdk/tests/metrics/export/test_export.py @@ -45,14 +45,13 @@ def test_export(self): meter, ("environment",), ) - kvp = {"environment": "staging"} - label_set = metrics.LabelSet(kvp) + labels = {"environment": "staging"} aggregator = CounterAggregator() - record = MetricRecord(aggregator, label_set, metric) - result = '{}(data="{}", label_set="{}", value={})'.format( + record = MetricRecord(aggregator, labels, metric) + result = '{}(data="{}", labels="{}", value={})'.format( ConsoleMetricsExporter.__name__, metric, - label_set.labels, + labels, aggregator.checkpoint, ) with mock.patch("sys.stdout") as mock_stdout: @@ -84,14 +83,14 @@ def test_checkpoint_set(self): ("environment",), ) aggregator.update(1.0) - label_set = metrics.LabelSet() + labels = () _batch_map = {} - _batch_map[(metric, label_set)] = aggregator + _batch_map[(metric, labels)] = aggregator batcher._batch_map = _batch_map records = batcher.checkpoint_set() self.assertEqual(len(records), 1) self.assertEqual(records[0].metric, metric) - self.assertEqual(records[0].label_set, label_set) + self.assertEqual(records[0].labels, labels) self.assertEqual(records[0].aggregator, aggregator) def test_checkpoint_set_empty(self): @@ -112,9 +111,9 @@ def test_finished_collection_stateless(self): ("environment",), ) aggregator.update(1.0) - label_set = metrics.LabelSet() + labels = () _batch_map = {} - _batch_map[(metric, label_set)] = aggregator + _batch_map[(metric, labels)] = aggregator batcher._batch_map = _batch_map batcher.finished_collection() self.assertEqual(len(batcher._batch_map), 0) @@ -132,9 +131,9 @@ def test_finished_collection_stateful(self): ("environment",), ) aggregator.update(1.0) - label_set = metrics.LabelSet() + labels = () _batch_map = {} - _batch_map[(metric, label_set)] = aggregator + _batch_map[(metric, labels)] = aggregator batcher._batch_map = _batch_map batcher.finished_collection() self.assertEqual(len(batcher._batch_map), 1) @@ -153,20 +152,18 @@ def test_ungrouped_batcher_process_exists(self): meter, ("environment",), ) - label_set = metrics.LabelSet() + labels = () _batch_map = {} - _batch_map[(metric, label_set)] = aggregator + _batch_map[(metric, labels)] = aggregator aggregator2.update(1.0) batcher._batch_map = _batch_map - record = metrics.Record(metric, label_set, aggregator2) + record = metrics.Record(metric, labels, aggregator2) batcher.process(record) self.assertEqual(len(batcher._batch_map), 1) - self.assertIsNotNone(batcher._batch_map.get((metric, label_set))) + self.assertIsNotNone(batcher._batch_map.get((metric, labels))) + self.assertEqual(batcher._batch_map.get((metric, labels)).current, 0) self.assertEqual( - batcher._batch_map.get((metric, label_set)).current, 0 - ) - self.assertEqual( - batcher._batch_map.get((metric, label_set)).checkpoint, 1.0 + batcher._batch_map.get((metric, labels)).checkpoint, 1.0 ) def test_ungrouped_batcher_process_not_exists(self): @@ -181,19 +178,17 @@ def test_ungrouped_batcher_process_not_exists(self): meter, ("environment",), ) - label_set = metrics.LabelSet() + labels = () _batch_map = {} aggregator.update(1.0) batcher._batch_map = _batch_map - record = metrics.Record(metric, label_set, aggregator) + record = metrics.Record(metric, labels, aggregator) batcher.process(record) self.assertEqual(len(batcher._batch_map), 1) - self.assertIsNotNone(batcher._batch_map.get((metric, label_set))) - self.assertEqual( - batcher._batch_map.get((metric, label_set)).current, 0 - ) + self.assertIsNotNone(batcher._batch_map.get((metric, labels))) + self.assertEqual(batcher._batch_map.get((metric, labels)).current, 0) self.assertEqual( - batcher._batch_map.get((metric, label_set)).checkpoint, 1.0 + batcher._batch_map.get((metric, labels)).checkpoint, 1.0 ) def test_ungrouped_batcher_process_not_stateful(self): @@ -208,19 +203,17 @@ def test_ungrouped_batcher_process_not_stateful(self): meter, ("environment",), ) - label_set = metrics.LabelSet() + labels = () _batch_map = {} aggregator.update(1.0) batcher._batch_map = _batch_map - record = metrics.Record(metric, label_set, aggregator) + record = metrics.Record(metric, labels, aggregator) batcher.process(record) self.assertEqual(len(batcher._batch_map), 1) - self.assertIsNotNone(batcher._batch_map.get((metric, label_set))) - self.assertEqual( - batcher._batch_map.get((metric, label_set)).current, 0 - ) + self.assertIsNotNone(batcher._batch_map.get((metric, labels))) + self.assertEqual(batcher._batch_map.get((metric, labels)).current, 0) self.assertEqual( - batcher._batch_map.get((metric, label_set)).checkpoint, 1.0 + batcher._batch_map.get((metric, labels)).checkpoint, 1.0 ) diff --git a/opentelemetry-sdk/tests/metrics/test_implementation.py b/opentelemetry-sdk/tests/metrics/test_implementation.py index 29b3b987f9a..1679f618341 100644 --- a/opentelemetry-sdk/tests/metrics/test_implementation.py +++ b/opentelemetry-sdk/tests/metrics/test_implementation.py @@ -14,7 +14,7 @@ import unittest -from opentelemetry.metrics import DefaultLabelSet, DefaultMeter, DefaultMetric +from opentelemetry.metrics import DefaultMeter, DefaultMetric from opentelemetry.sdk import metrics @@ -29,7 +29,5 @@ class TestMeterImplementation(unittest.TestCase): def test_meter(self): meter = metrics.MeterProvider().get_meter(__name__) metric = meter.create_metric("", "", "", float, metrics.Counter) - label_set = meter.get_label_set({"key1": "val1"}) self.assertNotIsInstance(meter, DefaultMeter) self.assertNotIsInstance(metric, DefaultMetric) - self.assertNotIsInstance(label_set, DefaultLabelSet) diff --git a/opentelemetry-sdk/tests/metrics/test_metrics.py b/opentelemetry-sdk/tests/metrics/test_metrics.py index 9212a9967c5..1bbe18b178b 100644 --- a/opentelemetry-sdk/tests/metrics/test_metrics.py +++ b/opentelemetry-sdk/tests/metrics/test_metrics.py @@ -47,9 +47,8 @@ def test_collect(self): counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) - counter.add(1.0, label_set) + labels = {"key1": "value1"} + counter.add(1.0, labels) meter.metrics.add(counter) meter.collect() self.assertTrue(batcher_mock.process.called) @@ -69,9 +68,8 @@ def test_collect_disabled_metric(self): counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys, False ) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) - counter.add(label_set, 1.0) + labels = {"key1": "value1"} + counter.add(1.0, labels) meter.metrics.add(counter) meter.collect() self.assertFalse(batcher_mock.process.called) @@ -83,7 +81,7 @@ def test_collect_observers(self): def callback(observer): self.assertIsInstance(observer, metrics_api.Observer) - observer.observe(45, meter.get_label_set(())) + observer.observe(45, {}) observer = metrics.Observer( callback, "name", "desc", "unit", int, meter, (), True @@ -96,20 +94,18 @@ def callback(observer): def test_record_batch(self): meter = metrics.MeterProvider().get_meter(__name__) label_keys = ("key1",) + labels = {"key1": "value1"} counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) record_tuples = [(counter, 1.0)] - meter.record_batch(label_set, record_tuples) - self.assertEqual(counter.bind(label_set).aggregator.current, 1.0) + meter.record_batch(labels, record_tuples) + self.assertEqual(counter.bind(labels).aggregator.current, 1.0) def test_record_batch_multiple(self): meter = metrics.MeterProvider().get_meter(__name__) label_keys = ("key1", "key2", "key3") - kvp = {"key1": "value1", "key2": "value2", "key3": "value3"} - label_set = meter.get_label_set(kvp) + labels = {"key1": "value1", "key2": "value2", "key3": "value3"} counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) @@ -117,25 +113,24 @@ def test_record_batch_multiple(self): "name", "desc", "unit", float, meter, label_keys ) record_tuples = [(counter, 1.0), (measure, 3.0)] - meter.record_batch(label_set, record_tuples) - self.assertEqual(counter.bind(label_set).aggregator.current, 1.0) + meter.record_batch(labels, record_tuples) + self.assertEqual(counter.bind(labels).aggregator.current, 1.0) self.assertEqual( - measure.bind(label_set).aggregator.current, (3.0, 3.0, 3.0, 1) + measure.bind(labels).aggregator.current, (3.0, 3.0, 3.0, 1) ) def test_record_batch_exists(self): meter = metrics.MeterProvider().get_meter(__name__) label_keys = ("key1",) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) + labels = {"key1": "value1"} counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) - counter.add(1.0, label_set) - bound_counter = counter.bind(label_set) + counter.add(1.0, labels) + bound_counter = counter.bind(labels) record_tuples = [(counter, 1.0)] - meter.record_batch(label_set, record_tuples) - self.assertEqual(counter.bind(label_set), bound_counter) + meter.record_batch(labels, record_tuples) + self.assertEqual(counter.bind(labels), bound_counter) self.assertEqual(bound_counter.aggregator.current, 2.0) def test_create_metric(self): @@ -191,37 +186,22 @@ def test_unregister_observer(self): meter.unregister_observer(observer) self.assertEqual(len(meter.observers), 0) - def test_get_label_set(self): - meter = metrics.MeterProvider().get_meter(__name__) - kvp = {"environment": "staging", "a": "z"} - label_set = meter.get_label_set(kvp) - label_set2 = meter.get_label_set(kvp) - labels = set([label_set, label_set2]) - self.assertEqual(len(labels), 1) - - def test_get_label_set_empty(self): - meter = metrics.MeterProvider().get_meter(__name__) - kvp = {} - label_set = meter.get_label_set(kvp) - self.assertEqual(label_set, metrics.EMPTY_LABEL_SET) - def test_direct_call_release_bound_instrument(self): meter = metrics.MeterProvider().get_meter(__name__) label_keys = ("key1",) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) + labels = {"key1": "value1"} counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) meter.metrics.add(counter) - counter.add(4.0, label_set) + counter.add(4.0, labels) measure = metrics.Measure( "name", "desc", "unit", float, meter, label_keys ) meter.metrics.add(measure) - measure.record(42.0, label_set) + measure.record(42.0, labels) self.assertEqual(len(counter.bound_instruments), 1) self.assertEqual(len(measure.bound_instruments), 1) @@ -234,21 +214,20 @@ def test_direct_call_release_bound_instrument(self): def test_release_bound_instrument(self): meter = metrics.MeterProvider().get_meter(__name__) label_keys = ("key1",) - kvp = {"key1": "value1"} - label_set = meter.get_label_set(kvp) + labels = {"key1": "value1"} counter = metrics.Counter( "name", "desc", "unit", float, meter, label_keys ) meter.metrics.add(counter) - bound_counter = counter.bind(label_set) + bound_counter = counter.bind(labels) bound_counter.add(4.0) measure = metrics.Measure( "name", "desc", "unit", float, meter, label_keys ) meter.metrics.add(measure) - bound_measure = measure.bind(label_set) + bound_measure = measure.bind(labels) bound_measure.record(42) bound_counter.release() @@ -268,13 +247,13 @@ class TestMetric(unittest.TestCase): def test_bind(self): meter = metrics.MeterProvider().get_meter(__name__) metric_types = [metrics.Counter, metrics.Measure] + labels = {"key": "value"} + key_labels = tuple(sorted(labels.items())) for _type in metric_types: metric = _type("name", "desc", "unit", int, meter, ("key",)) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) - bound_instrument = metric.bind(label_set) + bound_instrument = metric.bind(labels) self.assertEqual( - metric.bound_instruments.get(label_set), bound_instrument + metric.bound_instruments.get(key_labels), bound_instrument ) @@ -282,11 +261,10 @@ class TestCounter(unittest.TestCase): def test_add(self): meter = metrics.MeterProvider().get_meter(__name__) metric = metrics.Counter("name", "desc", "unit", int, meter, ("key",)) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) - bound_counter = metric.bind(label_set) - metric.add(3, label_set) - metric.add(2, label_set) + labels = {"key": "value"} + bound_counter = metric.bind(labels) + metric.add(3, labels) + metric.add(2, labels) self.assertEqual(bound_counter.aggregator.current, 5) @@ -294,12 +272,11 @@ class TestMeasure(unittest.TestCase): def test_record(self): meter = metrics.MeterProvider().get_meter(__name__) metric = metrics.Measure("name", "desc", "unit", int, meter, ("key",)) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) - bound_measure = metric.bind(label_set) + labels = {"key": "value"} + bound_measure = metric.bind(labels) values = (37, 42, 7) for val in values: - metric.record(val, label_set) + metric.record(val, labels) self.assertEqual( bound_measure.aggregator.current, (min(values), max(values), sum(values), len(values)), @@ -312,26 +289,25 @@ def test_observe(self): observer = metrics.Observer( None, "name", "desc", "unit", int, meter, ("key",), True ) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) + labels = {"key": "value"} + key_labels = tuple(sorted(labels.items())) values = (37, 42, 7, 21) for val in values: - observer.observe(val, label_set) + observer.observe(val, labels) self.assertEqual( - observer.aggregators[label_set].mmsc.current, + observer.aggregators[key_labels].mmsc.current, (min(values), max(values), sum(values), len(values)), ) - self.assertEqual(observer.aggregators[label_set].current, values[-1]) + self.assertEqual(observer.aggregators[key_labels].current, values[-1]) def test_observe_disabled(self): meter = metrics.MeterProvider().get_meter(__name__) observer = metrics.Observer( None, "name", "desc", "unit", int, meter, ("key",), False ) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) - observer.observe(37, label_set) + labels = {"key": "value"} + observer.observe(37, labels) self.assertEqual(len(observer.aggregators), 0) @mock.patch("opentelemetry.sdk.metrics.logger") @@ -340,9 +316,8 @@ def test_observe_incorrect_type(self, logger_mock): observer = metrics.Observer( None, "name", "desc", "unit", int, meter, ("key",), True ) - kvp = {"key": "value"} - label_set = meter.get_label_set(kvp) - observer.observe(37.0, label_set) + labels = {"key": "value"} + observer.observe(37.0, labels) self.assertEqual(len(observer.aggregators), 0) self.assertTrue(logger_mock.warning.called)