Skip to content

Commit ac8da0f

Browse files
committed
Create new aggregator per ViewData, config dict
1 parent 0be0964 commit ac8da0f

File tree

6 files changed

+90
-35
lines changed

6 files changed

+90
-35
lines changed

docs/examples/basic_meter/view.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,31 +60,32 @@
6060
# dropped from the aggregation
6161
counter_view1 = View(
6262
requests_counter,
63-
SumAggregator(),
63+
SumAggregator,
6464
label_keys=["environment"],
65-
config=ViewConfig.LABEL_KEYS,
65+
view_config=ViewConfig.LABEL_KEYS,
6666
)
6767
counter_view2 = View(
6868
requests_counter,
69-
MinMaxSumCountAggregator(),
69+
MinMaxSumCountAggregator,
7070
label_keys=["os_type"],
71-
config=ViewConfig.LABEL_KEYS,
71+
view_config=ViewConfig.LABEL_KEYS,
7272
)
7373
# This view has ViewConfig set to UNGROUPED, meaning all recorded metrics take
7474
# the labels directly without and consideration for label_keys
7575
counter_view3 = View(
7676
requests_counter,
77-
LastValueAggregator(),
77+
LastValueAggregator,
7878
label_keys=["environment"], # is not used due to ViewConfig.UNGROUPED
79-
config=ViewConfig.UNGROUPED,
79+
view_config=ViewConfig.UNGROUPED,
8080
)
8181
# This view uses the HistogramAggregator which accepts an option config
8282
# parameter to specify the bucket ranges
8383
size_view = View(
8484
requests_size,
85-
HistogramAggregator(config={"bounds": [20, 40, 60, 80, 100]}),
85+
HistogramAggregator,
8686
label_keys=["environment"], # is not used due to ViewConfig.UNGROUPED
87-
config=ViewConfig.UNGROUPED,
87+
aggregator_config={"bounds": [20, 40, 60, 80, 100]},
88+
view_config=ViewConfig.UNGROUPED,
8889
)
8990

9091
# Register the views to the view manager to use the views. Views MUST be

opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/aggregate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def __init__(self, config=None):
166166
super().__init__(config=config)
167167
self._lock = threading.Lock()
168168
self.last_update_timestamp = None
169-
boundaries = self.config.get("bounds", None)
169+
boundaries = self.config.get("bounds")
170170
if boundaries and self._validate_boundaries(boundaries):
171171
self._boundaries = boundaries
172172
else:

opentelemetry-sdk/src/opentelemetry/sdk/metrics/view.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,29 +74,40 @@ class View:
7474
def __init__(
7575
self,
7676
metric: InstrumentT,
77-
aggregator: Aggregator,
77+
aggregator: type,
78+
aggregator_config: dict = None,
7879
label_keys: Sequence[str] = None,
79-
config: ViewConfig = ViewConfig.UNGROUPED,
80+
view_config: ViewConfig = ViewConfig.UNGROUPED,
8081
):
8182
self.metric = metric
8283
self.aggregator = aggregator
84+
if aggregator_config is None:
85+
aggregator_config = {}
86+
self.aggregator_config = aggregator_config
8387
if label_keys is None:
8488
label_keys = []
8589
self.label_keys = sorted(label_keys)
86-
self.config = config
90+
self.view_config = view_config
8791

8892
# Uniqueness is based on metric, aggregator type, ordered label keys and ViewConfig
8993
def __hash__(self):
9094
return hash(
91-
(self.metric, self.aggregator, tuple(self.label_keys), self.config)
95+
(
96+
self.metric,
97+
self.aggregator,
98+
tuple(self.label_keys),
99+
tuple(self.aggregator_config),
100+
self.view_config,
101+
)
92102
)
93103

94104
def __eq__(self, other):
95105
return (
96106
self.metric == other.metric
97107
and self.aggregator.__class__ == other.aggregator.__class__
98108
and self.label_keys == other.label_keys
99-
and self.config == other.config
109+
and self.aggregator_config == other.aggregator_config
110+
and self.view_config == other.view_config
100111
)
101112

102113

@@ -132,7 +143,7 @@ def generate_view_datas(self, metric, labels):
132143
for view in views:
133144
updated_labels = []
134145
dropped_labels = []
135-
if view.config == ViewConfig.LABEL_KEYS:
146+
if view.view_config == ViewConfig.LABEL_KEYS:
136147
label_key_set = set(view.label_keys)
137148
for label in labels:
138149
# Only keep labels that are in configured label_keys
@@ -142,7 +153,7 @@ def generate_view_datas(self, metric, labels):
142153
dropped_labels.append(label)
143154
updated_labels = tuple(updated_labels)
144155
dropped_labels = tuple(dropped_labels)
145-
elif view.config == ViewConfig.UNGROUPED:
156+
elif view.view_config == ViewConfig.UNGROUPED:
146157
updated_labels = labels
147158
else:
148159
dropped_labels = labels
@@ -151,7 +162,7 @@ def generate_view_datas(self, metric, labels):
151162
view_datas.add(
152163
ViewData(
153164
tuple(updated_labels),
154-
view.aggregator,
165+
view.aggregator(view.aggregator_config),
155166
dropped_labels=dropped_labels,
156167
)
157168
)

opentelemetry-sdk/tests/metrics/export/test_exemplars.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -489,15 +489,14 @@ def test_histogram(self):
489489

490490
size_view = View(
491491
requests_size,
492-
HistogramAggregator(
493-
config={
494-
"bounds": [20, 40, 60, 80, 100],
495-
"num_exemplars": 1,
496-
"statistical_exemplars": True,
497-
}
498-
),
492+
HistogramAggregator,
493+
aggregator_config={
494+
"bounds": [20, 40, 60, 80, 100],
495+
"num_exemplars": 1,
496+
"statistical_exemplars": True,
497+
},
499498
label_keys=["environment"],
500-
config=ViewConfig.LABEL_KEYS,
499+
view_config=ViewConfig.LABEL_KEYS,
501500
)
502501

503502
meter.register_view(size_view)

opentelemetry-sdk/tests/metrics/test_metrics.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def test_collect_metrics(self):
8080
"name", "desc", "unit", float, metrics.Counter
8181
)
8282
labels = {"key1": "value1"}
83-
meter.register_view(View(counter, SumAggregator()))
83+
meter.register_view(View(counter, SumAggregator))
8484
counter.add(1.0, labels)
8585
meter.collect()
8686
self.assertTrue(batcher_mock.process.called)
@@ -108,7 +108,7 @@ def test_collect_disabled_metric(self):
108108
meter.batcher = batcher_mock
109109
counter = metrics.Counter("name", "desc", "unit", float, meter, False)
110110
labels = {"key1": "value1"}
111-
meter.register_view(View(counter, SumAggregator()))
111+
meter.register_view(View(counter, SumAggregator))
112112
counter.add(1.0, labels)
113113
meter.collect()
114114
self.assertFalse(batcher_mock.process.called)
@@ -137,8 +137,8 @@ def test_record_batch(self):
137137
valuerecorder = metrics.ValueRecorder(
138138
"name", "desc", "unit", float, meter
139139
)
140-
counter_v = View(counter, SumAggregator())
141-
measure_v = View(valuerecorder, MinMaxSumCountAggregator())
140+
counter_v = View(counter, SumAggregator)
141+
measure_v = View(valuerecorder, MinMaxSumCountAggregator)
142142
meter.register_view(counter_v)
143143
meter.register_view(measure_v)
144144
record_tuples = [(counter, 1.0), (valuerecorder, 3.0)]
@@ -241,7 +241,7 @@ def test_add(self):
241241
meter = metrics.MeterProvider().get_meter(__name__)
242242
metric = metrics.Counter("name", "desc", "unit", int, meter)
243243
labels = {"key": "value"}
244-
counter_v = View(metric, SumAggregator())
244+
counter_v = View(metric, SumAggregator)
245245
meter.register_view(counter_v)
246246
bound_mock = metric.bind(labels)
247247
metric.add(3, labels)
@@ -253,7 +253,7 @@ def test_add_non_decreasing_int_error(self, logger_mock):
253253
meter = metrics.MeterProvider().get_meter(__name__)
254254
metric = metrics.Counter("name", "desc", "unit", int, meter)
255255
labels = {"key": "value"}
256-
counter_v = View(metric, SumAggregator())
256+
counter_v = View(metric, SumAggregator)
257257
meter.register_view(counter_v)
258258
bound_counter = metric.bind(labels)
259259
metric.add(3, labels)
@@ -267,7 +267,7 @@ def test_add_non_decreasing_float_error(self, logger_mock):
267267
meter = metrics.MeterProvider().get_meter(__name__)
268268
metric = metrics.Counter("name", "desc", "unit", float, meter,)
269269
labels = {"key": "value"}
270-
counter_v = View(metric, SumAggregator())
270+
counter_v = View(metric, SumAggregator)
271271
meter.register_view(counter_v)
272272
bound_counter = metric.bind(labels)
273273
metric.add(3.3, labels)
@@ -286,7 +286,7 @@ def test_add(self):
286286
metric = metrics.UpDownCounter("name", "desc", "unit", int, meter,)
287287
labels = {"key": "value"}
288288
bound_counter = metric.bind(labels)
289-
counter_v = View(metric, SumAggregator())
289+
counter_v = View(metric, SumAggregator)
290290
meter.register_view(counter_v)
291291
metric.add(3, labels)
292292
metric.add(2, labels)
@@ -298,7 +298,7 @@ def test_record(self):
298298
meter = metrics.MeterProvider().get_meter(__name__)
299299
metric = metrics.ValueRecorder("name", "desc", "unit", int, meter,)
300300
labels = {"key": "value"}
301-
measure_v = View(metric, MinMaxSumCountAggregator())
301+
measure_v = View(metric, MinMaxSumCountAggregator)
302302
bound_valuerecorder = metric.bind(labels)
303303
meter.register_view(measure_v)
304304
values = (37, 42, 7)

opentelemetry-sdk/tests/metrics/test_view.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@
1616
from unittest import mock
1717

1818
from opentelemetry.sdk import metrics
19-
from opentelemetry.sdk.metrics import view
19+
from opentelemetry.sdk.metrics import Counter, view
2020
from opentelemetry.sdk.metrics.export import aggregate
21+
from opentelemetry.sdk.metrics.export.aggregate import SumAggregator
22+
from opentelemetry.sdk.metrics.export.controller import PushController
23+
from opentelemetry.sdk.metrics.export.in_memory_metrics_exporter import (
24+
InMemoryMetricsExporter,
25+
)
26+
from opentelemetry.sdk.metrics.view import View, ViewConfig
2127

2228

2329
class TestUtil(unittest.TestCase):
@@ -74,6 +80,44 @@ def test_default_aggregator(self, logger_mock):
7480
self.assertEqual(logger_mock.warning.call_count, 1)
7581

7682

83+
class TestPipeline(unittest.TestCase):
84+
def setUp(self):
85+
self.meter = metrics.MeterProvider(stateful=False).get_meter(__name__)
86+
self.exporter = InMemoryMetricsExporter()
87+
self.controller = PushController(self.meter, self.exporter, 30)
88+
89+
def tearDown(self):
90+
self.controller.shutdown()
91+
92+
def test_stateless_label_keys(self):
93+
test_counter = self.meter.create_metric(
94+
name="test_counter",
95+
description="description",
96+
unit="By",
97+
value_type=int,
98+
metric_type=Counter,
99+
)
100+
counter_view = View(
101+
test_counter,
102+
SumAggregator,
103+
label_keys=["environment"],
104+
view_config=ViewConfig.LABEL_KEYS,
105+
)
106+
107+
self.meter.register_view(counter_view)
108+
test_counter.add(6, {"environment": "production", "customer_id": 123})
109+
test_counter.add(5, {"environment": "production", "customer_id": 247})
110+
111+
self.controller.tick()
112+
113+
metric_data = self.exporter.get_exported_metrics()
114+
self.assertEqual(len(metric_data), 1)
115+
self.assertEqual(
116+
metric_data[0].labels, (("environment", "production"),)
117+
)
118+
self.assertEqual(metric_data[0].aggregator.checkpoint, 11)
119+
120+
77121
class DummyMetric(metrics.Metric):
78122
# pylint: disable=W0231
79123
def __init__(self):

0 commit comments

Comments
 (0)