Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6a88987

Browse files
ocelotlaabmass
andauthored
Add measurement consumer (open-telemetry#2339)
* Add measurement consumer * Fix lint * Address comments * Update opentelemetry-sdk/src/opentelemetry/sdk/_metrics/instrument.py Co-authored-by: Aaron Abbott <[email protected]> * Rename Serial to Synchronous * Fix asynchronous instrument registering bug * Fix type * Use right path * Fix lint * Fix circular import * Pass name first * Implement different fix for circular import Co-authored-by: Aaron Abbott <[email protected]>
1 parent 9e78bcb commit 6a88987

File tree

6 files changed

+265
-25
lines changed

6 files changed

+265
-25
lines changed

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

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
ObservableUpDownCounter,
4141
UpDownCounter,
4242
)
43+
from opentelemetry.sdk._metrics.measurement_consumer import (
44+
MeasurementConsumer,
45+
SynchronousMeasurementConsumer,
46+
)
4347
from opentelemetry.sdk._metrics.metric_reader import MetricReader
4448
from opentelemetry.sdk.resources import Resource
4549
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
@@ -51,48 +55,94 @@ class Meter(APIMeter):
5155
def __init__(
5256
self,
5357
instrumentation_info: InstrumentationInfo,
54-
meter_provider: APIMeterProvider,
58+
measurement_consumer: MeasurementConsumer,
5559
):
5660
super().__init__(instrumentation_info)
5761
self._instrumentation_info = instrumentation_info
58-
self._meter_provider = meter_provider
62+
self._measurement_consumer = measurement_consumer
5963

6064
def create_counter(self, name, unit=None, description=None) -> APICounter:
61-
return Counter(self._instrumentation_info, name, unit, description)
65+
return Counter(
66+
name,
67+
self._instrumentation_info,
68+
self._measurement_consumer,
69+
unit,
70+
description,
71+
)
6272

6373
def create_up_down_counter(
6474
self, name, unit=None, description=None
6575
) -> APIUpDownCounter:
6676
return UpDownCounter(
67-
self._instrumentation_info, name, unit, description
77+
name,
78+
self._instrumentation_info,
79+
self._measurement_consumer,
80+
unit,
81+
description,
6882
)
6983

7084
def create_observable_counter(
7185
self, name, callback, unit=None, description=None
7286
) -> APIObservableCounter:
73-
return ObservableCounter(
74-
self._instrumentation_info, name, callback, unit, description
87+
88+
instrument = ObservableCounter(
89+
name,
90+
self._instrumentation_info,
91+
self._measurement_consumer,
92+
callback,
93+
unit,
94+
description,
7595
)
7696

97+
self._measurement_consumer.register_asynchronous_instrument(instrument)
98+
99+
return instrument
100+
77101
def create_histogram(
78102
self, name, unit=None, description=None
79103
) -> APIHistogram:
80-
return Histogram(self._instrumentation_info, name, unit, description)
104+
return Histogram(
105+
name,
106+
self._instrumentation_info,
107+
self._measurement_consumer,
108+
unit,
109+
description,
110+
)
81111

82112
def create_observable_gauge(
83113
self, name, callback, unit=None, description=None
84114
) -> APIObservableGauge:
85-
return ObservableGauge(
86-
self._instrumentation_info, name, callback, unit, description
115+
116+
instrument = ObservableGauge(
117+
name,
118+
self._instrumentation_info,
119+
self._measurement_consumer,
120+
callback,
121+
unit,
122+
description,
87123
)
88124

125+
self._measurement_consumer.register_asynchronous_instrument(instrument)
126+
127+
return instrument
128+
89129
def create_observable_up_down_counter(
90130
self, name, callback, unit=None, description=None
91131
) -> APIObservableUpDownCounter:
92-
return ObservableUpDownCounter(
93-
self._instrumentation_info, name, callback, unit, description
132+
133+
instrument = ObservableUpDownCounter(
134+
name,
135+
self._instrumentation_info,
136+
self._measurement_consumer,
137+
callback,
138+
unit,
139+
description,
94140
)
95141

142+
self._measurement_consumer.register_asynchronous_instrument(instrument)
143+
144+
return instrument
145+
96146

97147
class MeterProvider(APIMeterProvider):
98148
"""See `opentelemetry._metrics.MeterProvider`."""
@@ -106,13 +156,15 @@ def __init__(
106156
self._lock = Lock()
107157
self._atexit_handler = None
108158

159+
self._measurement_consumer = SynchronousMeasurementConsumer()
160+
109161
if shutdown_on_exit:
110162
self._atexit_handler = register(self.shutdown)
111163

112164
self._metric_readers = metric_readers
113165

114166
for metric_reader in self._metric_readers:
115-
metric_reader._register_meter_provider(self)
167+
metric_reader._register_measurement_consumer(self)
116168

117169
self._resource = resource
118170
self._shutdown = False
@@ -169,4 +221,7 @@ def get_meter(
169221
)
170222
return _DefaultMeter(name, version=version, schema_url=schema_url)
171223

172-
return Meter(InstrumentationInfo(name, version, schema_url), self)
224+
return Meter(
225+
InstrumentationInfo(name, version, schema_url),
226+
self._measurement_consumer,
227+
)

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,42 @@
3030
)
3131
from opentelemetry._metrics.instrument import UpDownCounter as APIUpDownCounter
3232
from opentelemetry.sdk._metrics.measurement import Measurement
33+
from opentelemetry.sdk._metrics.measurement_consumer import MeasurementConsumer
3334
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
3435

3536

3637
class _Synchronous:
3738
def __init__(
3839
self,
39-
instrumentation_info: InstrumentationInfo,
4040
name: str,
41+
instrumentation_info: InstrumentationInfo,
42+
measurement_consumer: MeasurementConsumer,
4143
unit: str = "",
4244
description: str = "",
4345
):
46+
self.name = name
47+
self.unit = unit
48+
self.description = description
4449
self._instrumentation_info = instrumentation_info
50+
self._measurement_consumer = measurement_consumer
4551
super().__init__(name, unit=unit, description=description)
4652

4753

4854
class _Asynchronous:
4955
def __init__(
5056
self,
51-
instrumentation_info: InstrumentationInfo,
5257
name: str,
58+
instrumentation_info: InstrumentationInfo,
59+
measurement_consumer: MeasurementConsumer,
5360
callback: CallbackT,
5461
unit: str = "",
5562
description: str = "",
5663
):
57-
64+
self.name = name
65+
self.unit = unit
66+
self.description = description
5867
self._instrumentation_info = instrumentation_info
68+
self._measurement_consumer = measurement_consumer
5969
super().__init__(name, callback, unit=unit, description=description)
6070

6171
self._callback = callback
@@ -79,12 +89,18 @@ def add(
7989
if amount < 0:
8090
raise Exception("amount must be non negative")
8191

92+
self._measurement_consumer.consume_measurement(
93+
Measurement(amount, attributes)
94+
)
95+
8296

8397
class UpDownCounter(_Synchronous, APIUpDownCounter):
8498
def add(
8599
self, amount: Union[int, float], attributes: Dict[str, str] = None
86100
):
87-
pass
101+
self._measurement_consumer.consume_measurement(
102+
Measurement(amount, attributes)
103+
)
88104

89105

90106
class ObservableCounter(_Asynchronous, APIObservableCounter):
@@ -97,7 +113,9 @@ class ObservableUpDownCounter(_Asynchronous, APIObservableUpDownCounter):
97113

98114
class Histogram(_Synchronous, APIHistogram):
99115
def record(self, amount, attributes=None):
100-
pass
116+
self._measurement_consumer.consume_measurement(
117+
Measurement(amount, attributes)
118+
)
101119

102120

103121
class ObservableGauge(_Asynchronous, APIObservableGauge):
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from abc import ABC, abstractmethod
16+
from typing import TYPE_CHECKING, Iterable
17+
18+
from opentelemetry.sdk._metrics.aggregation import AggregationTemporality
19+
from opentelemetry.sdk._metrics.measurement import Measurement
20+
from opentelemetry.sdk._metrics.metric_reader import MetricReader
21+
from opentelemetry.sdk._metrics.point import Metric
22+
23+
if TYPE_CHECKING:
24+
from opentelemetry.sdk._metrics.instrument import _Asynchronous
25+
26+
27+
class MeasurementConsumer(ABC):
28+
@abstractmethod
29+
def consume_measurement(self, measurement: Measurement) -> None:
30+
pass
31+
32+
@abstractmethod
33+
def register_asynchronous_instrument(self, instrument: "_Asynchronous"):
34+
pass
35+
36+
@abstractmethod
37+
def collect(
38+
self, metric_reader: MetricReader, temporality: AggregationTemporality
39+
) -> Iterable[Metric]:
40+
pass
41+
42+
43+
class SynchronousMeasurementConsumer(MeasurementConsumer):
44+
def consume_measurement(self, measurement: Measurement) -> None:
45+
pass
46+
47+
def register_asynchronous_instrument(
48+
self, instrument: "_Asynchronous"
49+
) -> None:
50+
pass
51+
52+
def collect(
53+
self, metric_reader: MetricReader, temporality: AggregationTemporality
54+
) -> Iterable[Metric]:
55+
pass

opentelemetry-sdk/tests/metrics/test_instrument.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ def test_callable_callback(self):
2727
def callback():
2828
return [1, 2, 3]
2929

30-
observable_gauge = ObservableGauge(Mock(), "name", callback)
30+
observable_gauge = ObservableGauge("name", Mock(), Mock(), callback)
3131

3232
self.assertEqual(observable_gauge.callback(), [1, 2, 3])
3333

3434
def test_generator_callback(self):
3535
def callback():
3636
yield [1, 2, 3]
3737

38-
observable_gauge = ObservableGauge(Mock(), "name", callback())
38+
observable_gauge = ObservableGauge("name", Mock(), Mock(), callback())
3939

4040
self.assertEqual(observable_gauge.callback(), [1, 2, 3])
4141

@@ -45,15 +45,19 @@ def test_callable_callback(self):
4545
def callback():
4646
return [1, 2, 3]
4747

48-
observable_counter = ObservableCounter(Mock(), "name", callback)
48+
observable_counter = ObservableCounter(
49+
"name", Mock(), Mock(), callback
50+
)
4951

5052
self.assertEqual(observable_counter.callback(), [1, 2, 3])
5153

5254
def test_generator_callback(self):
5355
def callback():
5456
yield [1, 2, 3]
5557

56-
observable_counter = ObservableCounter(Mock(), "name", callback())
58+
observable_counter = ObservableCounter(
59+
"name", Mock(), Mock(), callback()
60+
)
5761

5862
self.assertEqual(observable_counter.callback(), [1, 2, 3])
5963

@@ -64,7 +68,7 @@ def callback():
6468
return [1, 2, 3]
6569

6670
observable_up_down_counter = ObservableUpDownCounter(
67-
Mock(), "name", callback
71+
"name", Mock(), Mock(), callback
6872
)
6973

7074
self.assertEqual(observable_up_down_counter.callback(), [1, 2, 3])
@@ -74,7 +78,7 @@ def callback():
7478
yield [1, 2, 3]
7579

7680
observable_up_down_counter = ObservableUpDownCounter(
77-
Mock(), "name", callback()
81+
"name", Mock(), Mock(), callback()
7882
)
7983

8084
self.assertEqual(observable_up_down_counter.callback(), [1, 2, 3])

0 commit comments

Comments
 (0)