Skip to content

Commit 1f85268

Browse files
ocelotlaabmasssrikanthccv
authored
Adds Aggregation and instruments as part of Metrics SDK (#2234)
* Adds metrics API (#1887) * Adds metric prototype Fixes #1835 * Fix docs * Add API metrics doc * Add missing docs * Add files * Adding docs * Refactor to _initialize * Refactor initialize * Add more documentation * Add exporter test * Add process * Fix tests * Try to add aggregator_class argument Tests are failing here * Fix instrument parent classes * Test default aggregator * WIP * Add prototype test * Tests passing again * Use right counters * All tests passing * Rearrange instrument storage * Fix tests * Add HTTP server test * WIP * WIP * Add prototype * WIP * Fail the test * WIP * WIP * WIP * WIP * Add views * Discard instruments via views * Fix tests * WIP * WIP * Fix lint * WIP * Fix test * Fix lint * Fix method * Fix lint * Mypy workaround * Skip if 3.6 * Fix lint * Add reason * Fix 3.6 * Fix run * Fix lint * Remove SDK metrics * Remove SDK docs * Remove metrics * Remove assertnotraises mixin * Revert sdk docs conf * Remove SDK env var changes * Fix unit checking * Define positional-only arguments * Add Metrics plans * Add API tests * WIP * WIP test * WIP * WIP * WIP * Set provider test passing * Use a fixture * Add test for get_provider * Rename tests * WIP * WIP * WIP * WIP * Remove non specific requirement * Add meter requirements * Put all meter provider tests in one file * Add meter tests * Make attributes be passed as a dictionary * Make some interfaces private * Log an error instead * Remove ASCII flag * Add CHANGELOG entry * Add instrument tests * All tests passing * Add test * Add name tests * Add unit tests * Add description tests * Add counter tests * Add more tests * Add Histogram tests * Add observable gauge tests * Add updowncounter tests * Add observableupdowncounter tests * Fix lint * Fix docs * Fix lint * Ignore mypy * Remove useless pylint skip * Remove useless pylint skip * Remove useless pylint skip * Remove useless pylint skip * Remove useless pylint skip * Add locks to meter and meterprovider * Add lock to instruments * Fix fixmes * Fix lint * Add documentation placeholder * Remove blank line as requested. * Do not override Rlock * Remove unecessary super calls * Add missing super calls * Remove plan files * Add missing parameters * Rename observe to callback * Fix lint * Rename to secure_instrument_name * Remove locks * Fix lint * Remove args and kwargs * Remove implementation that gives meters access to meter provider * Allow creating async instruments with either a callback function or generator * add additional test with callback form of observable counter * add a test/example that reads measurements from proc stat * implement cpu time integration test with generator too Co-authored-by: Aaron Abbott <[email protected]> * Make measurement a concrete class (#2153) * Make Measurement a concrete class * comments * update changelog * Return proxy instruments from ProxyMeter (#2169) * Merge main 4 (#2236) * Add MeterProvider and Meter to the SDK Fixes #2200 * Add FIXMEs * Fix docstring * Add FIXME * Fix meter return * Log an error if a force flush fails * Add FIXME * Fix lint * Remove SDK API module * Unregister * Fix API names * Return _DefaultMeter * Remove properties * Pass MeterProvider as a parameter to __init__ * Add FIXMEs * Add FIXMEs * Fix lint * Add Aggregation to the metrics SDK Fixes #2229 * lint fix wip * Fix lint * Add proto to setup.cfg * Add timestamp for last value * Rename modules to be private * Fix paths * Set value in concrete classes init * Fix test * Fix lint * Remove temporalities * Use frozenset as key * Test instruments * Handle min, max and sum in explicit bucket histogram aggregator * Add test for negative values * Remove collect method from aggregations * Add make_point_and_reset * Remove add implementation * Remove _Synchronous * Update opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py Co-authored-by: Aaron Abbott <[email protected]> * Requested fixes * Remove NoneAggregation * Add changelog entry * Fix tests * Fix boundaries * More fixes * Update CHANGELOG.md Co-authored-by: Srikanth Chekuri <[email protected]> Co-authored-by: Aaron Abbott <[email protected]> Co-authored-by: Srikanth Chekuri <[email protected]>
1 parent db75dae commit 1f85268

File tree

4 files changed

+426
-0
lines changed

4 files changed

+426
-0
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.7.0-0.26b0...HEAD)
88

9+
- Adds Aggregation and instruments as part of Metrics SDK
10+
([#2234](https://github.com/open-telemetry/opentelemetry-python/pull/2234))
11+
912
## [1.7.1-0.26b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.7.0-0.26b0) - 2021-11-11
1013

1114

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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 collections import OrderedDict
17+
from logging import getLogger
18+
from math import inf
19+
20+
from opentelemetry._metrics.instrument import _Monotonic
21+
from opentelemetry.util._time import _time_ns
22+
23+
_logger = getLogger(__name__)
24+
25+
26+
class Aggregation(ABC):
27+
@property
28+
def value(self):
29+
return self._value # pylint: disable=no-member
30+
31+
@abstractmethod
32+
def aggregate(self, value):
33+
pass
34+
35+
@abstractmethod
36+
def make_point_and_reset(self):
37+
"""
38+
Atomically return a point for the current value of the metric and reset the internal state.
39+
"""
40+
41+
42+
class SumAggregation(Aggregation):
43+
"""
44+
This aggregation collects data for the SDK sum metric point.
45+
"""
46+
47+
def __init__(self, instrument):
48+
self._value = 0
49+
50+
def aggregate(self, value):
51+
self._value = self._value + value
52+
53+
def make_point_and_reset(self):
54+
pass
55+
56+
57+
class LastValueAggregation(Aggregation):
58+
59+
"""
60+
This aggregation collects data for the SDK sum metric point.
61+
"""
62+
63+
def __init__(self, instrument):
64+
self._value = None
65+
self._timestamp = _time_ns()
66+
67+
def aggregate(self, value):
68+
self._value = value
69+
self._timestamp = _time_ns()
70+
71+
def make_point_and_reset(self):
72+
pass
73+
74+
75+
class ExplicitBucketHistogramAggregation(Aggregation):
76+
77+
"""
78+
This aggregation collects data for the SDK sum metric point.
79+
"""
80+
81+
def __init__(
82+
self,
83+
instrument,
84+
*args,
85+
boundaries=(0, 5, 10, 25, 50, 75, 100, 250, 500, 1000),
86+
record_min_max=True,
87+
):
88+
super().__init__()
89+
self._value = OrderedDict([(key, 0) for key in (*boundaries, inf)])
90+
self._min = inf
91+
self._max = -inf
92+
self._sum = 0
93+
self._instrument = instrument
94+
self._record_min_max = record_min_max
95+
96+
@property
97+
def min(self):
98+
if not self._record_min_max:
99+
_logger.warning("Min is not being recorded")
100+
101+
return self._min
102+
103+
@property
104+
def max(self):
105+
if not self._record_min_max:
106+
_logger.warning("Max is not being recorded")
107+
108+
return self._max
109+
110+
@property
111+
def sum(self):
112+
if isinstance(self._instrument, _Monotonic):
113+
return self._sum
114+
115+
_logger.warning(
116+
"Sum is not filled out when the associated "
117+
"instrument is not monotonic"
118+
)
119+
return None
120+
121+
def aggregate(self, value):
122+
if self._record_min_max:
123+
self._min = min(self._min, value)
124+
self._max = max(self._max, value)
125+
126+
if isinstance(self._instrument, _Monotonic):
127+
self._sum += value
128+
129+
for key in self._value.keys():
130+
131+
if value < key:
132+
self._value[key] = self._value[key] + value
133+
134+
break
135+
136+
def make_point_and_reset(self):
137+
pass
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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+
# pylint: disable=function-redefined
16+
# pylint: disable=dangerous-default-value
17+
# Classes in this module use dictionaries as default arguments. This is
18+
# considered dangerous by pylint because the default dictionary is shared by
19+
# all instances. Implementations of these classes must not make any change to
20+
# this default dictionary in __init__.
21+
22+
from opentelemetry._metrics.instrument import (
23+
Counter,
24+
Histogram,
25+
ObservableCounter,
26+
ObservableGauge,
27+
ObservableUpDownCounter,
28+
UpDownCounter,
29+
)
30+
from opentelemetry.sdk._metrics.aggregation import (
31+
ExplicitBucketHistogramAggregation,
32+
LastValueAggregation,
33+
SumAggregation,
34+
)
35+
36+
37+
class _Instrument:
38+
def __init__(
39+
self,
40+
name,
41+
unit="",
42+
description="",
43+
aggregation=None,
44+
aggregation_config={},
45+
):
46+
self._attributes_aggregations = {}
47+
self._aggregation = aggregation
48+
self._aggregation_config = aggregation_config
49+
aggregation(self, **aggregation_config)
50+
51+
52+
class Counter(_Instrument, Counter):
53+
def __init__(
54+
self,
55+
name,
56+
unit="",
57+
description="",
58+
aggregation=SumAggregation,
59+
aggregation_config={},
60+
):
61+
super().__init__(
62+
name,
63+
unit=unit,
64+
description=description,
65+
aggregation=aggregation,
66+
aggregation_config=aggregation_config,
67+
)
68+
69+
70+
class UpDownCounter(_Instrument, UpDownCounter):
71+
def __init__(
72+
self,
73+
name,
74+
unit="",
75+
description="",
76+
aggregation=SumAggregation,
77+
aggregation_config={},
78+
):
79+
super().__init__(
80+
name,
81+
unit=unit,
82+
description=description,
83+
aggregation=aggregation,
84+
aggregation_config=aggregation_config,
85+
)
86+
87+
88+
class ObservableCounter(_Instrument, ObservableCounter):
89+
def __init__(
90+
self,
91+
name,
92+
callback,
93+
unit="",
94+
description="",
95+
aggregation=SumAggregation,
96+
aggregation_config={},
97+
):
98+
super().__init__(
99+
name,
100+
unit=unit,
101+
description=description,
102+
aggregation=aggregation,
103+
aggregation_config=aggregation_config,
104+
)
105+
106+
107+
class ObservableUpDownCounter(_Instrument, ObservableUpDownCounter):
108+
def __init__(
109+
self,
110+
name,
111+
callback,
112+
unit="",
113+
description="",
114+
aggregation=SumAggregation,
115+
aggregation_config={},
116+
):
117+
super().__init__(
118+
name,
119+
unit=unit,
120+
description=description,
121+
aggregation=aggregation,
122+
aggregation_config=aggregation_config,
123+
)
124+
125+
126+
class Histogram(_Instrument, Histogram):
127+
def __init__(
128+
self,
129+
name,
130+
unit="",
131+
description="",
132+
aggregation=ExplicitBucketHistogramAggregation,
133+
aggregation_config={},
134+
):
135+
super().__init__(
136+
name,
137+
unit=unit,
138+
description=description,
139+
aggregation=aggregation,
140+
aggregation_config=aggregation_config,
141+
)
142+
143+
144+
class ObservableGauge(_Instrument, ObservableGauge):
145+
def __init__(
146+
self,
147+
name,
148+
callback,
149+
unit="",
150+
description="",
151+
aggregation=LastValueAggregation,
152+
aggregation_config={},
153+
):
154+
super().__init__(
155+
name,
156+
unit=unit,
157+
description=description,
158+
aggregation=aggregation,
159+
aggregation_config=aggregation_config,
160+
)

0 commit comments

Comments
 (0)