Skip to content

Commit 5e0e2de

Browse files
authored
Fix ViewInstrumentMatch to create new aggregation for each attribute set (#2503)
1 parent 6fc9e4c commit 5e0e2de

File tree

6 files changed

+116
-137
lines changed

6 files changed

+116
-137
lines changed

opentelemetry-sdk/src/opentelemetry/sdk/_metrics/_view_instrument_match.py

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,45 @@
1515

1616
from logging import getLogger
1717
from threading import Lock
18-
from typing import Iterable, Set
18+
from typing import TYPE_CHECKING, Iterable
1919

2020
from opentelemetry.sdk._metrics.aggregation import (
21-
_Aggregation,
2221
_convert_aggregation_temporality,
2322
)
2423
from opentelemetry.sdk._metrics.measurement import Measurement
2524
from opentelemetry.sdk._metrics.point import AggregationTemporality, Metric
26-
from opentelemetry.sdk.resources import Resource
27-
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
25+
from opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration
26+
from opentelemetry.sdk._metrics.view import View
27+
28+
if TYPE_CHECKING:
29+
from opentelemetry.sdk._metrics.instrument import _Instrument
2830

2931
_logger = getLogger(__name__)
3032

3133

3234
class _ViewInstrumentMatch:
3335
def __init__(
3436
self,
35-
name: str,
36-
unit: str,
37-
description: str,
38-
aggregation: _Aggregation,
39-
instrumentation_info: InstrumentationInfo,
40-
resource: Resource,
41-
attribute_keys: Set[str],
37+
view: View,
38+
instrument: "_Instrument",
39+
sdk_config: SdkConfiguration,
4240
):
43-
self._name = name
44-
self._unit = unit
45-
self._description = description
46-
self._aggregation = aggregation
47-
self._instrumentation_info = instrumentation_info
48-
self._resource = resource
49-
self._attribute_keys = attribute_keys
41+
self._view = view
42+
self._instrument = instrument
43+
self._sdk_config = sdk_config
5044
self._attributes_aggregation = {}
5145
self._attributes_previous_point = {}
5246
self._lock = Lock()
5347

48+
# pylint: disable=protected-access
5449
def consume_measurement(self, measurement: Measurement) -> None:
5550

56-
if self._attribute_keys:
51+
if self._view._attribute_keys is not None:
5752

5853
attributes = {}
5954

60-
for key, value in measurement.attributes.items():
61-
if key in self._attribute_keys:
55+
for key, value in (measurement.attributes or {}).items():
56+
if key in self._view._attribute_keys:
6257
attributes[key] = value
6358
elif measurement.attributes is not None:
6459
attributes = measurement.attributes
@@ -67,9 +62,18 @@ def consume_measurement(self, measurement: Measurement) -> None:
6762

6863
attributes = frozenset(attributes.items())
6964

70-
if attributes not in self._attributes_aggregation.keys():
65+
if attributes not in self._attributes_aggregation:
7166
with self._lock:
72-
self._attributes_aggregation[attributes] = self._aggregation
67+
if attributes not in self._attributes_aggregation:
68+
if self._view._aggregation:
69+
aggregation = (
70+
self._view._aggregation._create_aggregation(
71+
self._instrument
72+
)
73+
)
74+
else:
75+
aggregation = self._instrument._default_aggregation
76+
self._attributes_aggregation[attributes] = aggregation
7377

7478
self._attributes_aggregation[attributes].aggregate(measurement)
7579

@@ -100,11 +104,14 @@ def collect(self, temporality: int) -> Iterable[Metric]:
100104

101105
yield Metric(
102106
attributes=dict(attributes),
103-
description=self._description,
104-
instrumentation_info=self._instrumentation_info,
105-
name=self._name,
106-
resource=self._resource,
107-
unit=self._unit,
107+
description=(
108+
self._view._description
109+
or self._instrument.description
110+
),
111+
instrumentation_info=self._instrument.instrumentation_info,
112+
name=self._view._name or self._instrument.name,
113+
resource=self._sdk_config.resource,
114+
unit=self._instrument.unit,
108115
point=_convert_aggregation_temporality(
109116
previous_point,
110117
current_point,

opentelemetry-sdk/src/opentelemetry/sdk/_metrics/measurement.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
# limitations under the License.
1414

1515
from dataclasses import dataclass
16-
from typing import Union
16+
from typing import TYPE_CHECKING, Union
1717

18-
from opentelemetry._metrics.instrument import Instrument
1918
from opentelemetry.util.types import Attributes
2019

20+
if TYPE_CHECKING:
21+
from opentelemetry.sdk._metrics.instrument import _Instrument
22+
2123

2224
@dataclass(frozen=True)
2325
class Measurement:
2426
value: Union[int, float]
25-
instrument: Instrument
27+
instrument: "_Instrument"
2628
attributes: Attributes = None

opentelemetry-sdk/src/opentelemetry/sdk/_metrics/metric_reader_storage.py

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration
2626
from opentelemetry.sdk._metrics.view import View
2727

28+
_DEFAULT_VIEW = View(instrument_name="")
29+
2830

2931
class MetricReaderStorage:
3032
"""The SDK's storage for a given reader"""
@@ -55,27 +57,11 @@ def _get_or_init_view_instrument_match(
5557
for view in self._sdk_config.views:
5658
# pylint: disable=protected-access
5759
if view._match(instrument):
58-
59-
if view._aggregation is not None:
60-
aggregation = view._aggregation._create_aggregation(
61-
instrument
62-
)
63-
else:
64-
aggregation = instrument._default_aggregation
65-
6660
view_instrument_matches.append(
6761
_ViewInstrumentMatch(
68-
name=view._name or instrument.name,
69-
unit=instrument.unit,
70-
description=(
71-
view._description or instrument.description
72-
),
73-
aggregation=aggregation,
74-
instrumentation_info=(
75-
instrument.instrumentation_info
76-
),
77-
resource=self._sdk_config.resource,
78-
attribute_keys=view._attribute_keys,
62+
view=view,
63+
instrument=instrument,
64+
sdk_config=self._sdk_config,
7965
)
8066
)
8167

@@ -86,14 +72,9 @@ def _get_or_init_view_instrument_match(
8672
):
8773
view_instrument_matches.append(
8874
_ViewInstrumentMatch(
89-
name=instrument.name,
90-
unit=instrument.unit,
91-
description=instrument.description,
92-
# pylint: disable=protected-access
93-
aggregation=instrument._default_aggregation,
94-
instrumentation_info=instrument.instrumentation_info,
95-
resource=self._sdk_config.resource,
96-
attribute_keys=set(),
75+
view=_DEFAULT_VIEW,
76+
instrument=instrument,
77+
sdk_config=self._sdk_config,
9778
)
9879
)
9980
self._view_instrument_match[instrument] = view_instrument_matches

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ class the instrument must be to match the view.
127127

128128
self._description = description
129129
self._attribute_keys = attribute_keys
130-
131-
if self._attribute_keys is None:
132-
self._attribute_keys = set()
133-
134130
self._aggregation = aggregation
135131

136132
# pylint: disable=too-many-return-statements

opentelemetry-sdk/tests/metrics/test_metric_reader_storage.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,12 @@
1414

1515
from unittest.mock import Mock, patch
1616

17-
from opentelemetry.sdk._metrics.aggregation import SumAggregation
18-
from opentelemetry.sdk._metrics.instrument import Counter
1917
from opentelemetry.sdk._metrics.measurement import Measurement
2018
from opentelemetry.sdk._metrics.metric_reader_storage import (
2119
MetricReaderStorage,
2220
)
2321
from opentelemetry.sdk._metrics.point import AggregationTemporality
2422
from opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration
25-
from opentelemetry.sdk._metrics.view import View
2623
from opentelemetry.test.concurrency_test import ConcurrencyTestBase, MockFunc
2724

2825

@@ -162,38 +159,6 @@ def send_measurement():
162159
# _ViewInstrumentMatch constructor should have only been called once
163160
self.assertEqual(mock_view_instrument_match_ctor.call_count, 1)
164161

165-
def test_aggregations(self):
166-
167-
view = View(instrument_name="counter*", aggregation=SumAggregation())
168-
169-
metric_reader_storage = MetricReaderStorage(
170-
SdkConfiguration(
171-
resource=Mock(),
172-
metric_readers=(),
173-
views=(view,),
174-
enable_default_view=True,
175-
)
176-
)
177-
178-
counter_0 = Counter("counter_0", Mock(), Mock())
179-
counter_1 = Counter("counter_1", Mock(), Mock())
180-
181-
metric_reader_storage.consume_measurement(Measurement(1, counter_0))
182-
metric_reader_storage.consume_measurement(Measurement(2, counter_1))
183-
184-
self.assertEqual(
185-
1,
186-
metric_reader_storage._view_instrument_match[counter_0][
187-
0
188-
]._aggregation._value,
189-
)
190-
self.assertEqual(
191-
2,
192-
metric_reader_storage._view_instrument_match[counter_1][
193-
0
194-
]._aggregation._value,
195-
)
196-
197162
@patch(
198163
"opentelemetry.sdk._metrics.metric_reader_storage._ViewInstrumentMatch"
199164
)

0 commit comments

Comments
 (0)