Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Aggregation and instruments as part of Metrics SDK #2234

Merged
merged 49 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
082d553
Adds metrics API (#1887)
ocelotl Sep 24, 2021
162acb9
Make measurement a concrete class (#2153)
aabmass Sep 29, 2021
22b561d
Return proxy instruments from ProxyMeter (#2169)
aabmass Oct 14, 2021
6e8b1a7
Merge main 4 (#2236)
ocelotl Oct 25, 2021
4b448d8
Add MeterProvider and Meter to the SDK
ocelotl Oct 19, 2021
aa2b1f0
Add FIXMEs
ocelotl Oct 25, 2021
881b04a
Fix docstring
ocelotl Oct 25, 2021
e3816eb
Add FIXME
ocelotl Oct 25, 2021
611ef1f
Fix meter return
ocelotl Oct 25, 2021
c7f0dae
Log an error if a force flush fails
ocelotl Oct 25, 2021
0ab82ba
Add FIXME
ocelotl Oct 25, 2021
a01198f
Fix lint
ocelotl Oct 25, 2021
558c9ac
Remove SDK API module
ocelotl Oct 27, 2021
3c119a2
Unregister
ocelotl Oct 27, 2021
899c064
Fix API names
ocelotl Oct 28, 2021
bdce736
Return _DefaultMeter
ocelotl Oct 28, 2021
8cff4ca
Remove properties
ocelotl Oct 28, 2021
f019207
Pass MeterProvider as a parameter to __init__
ocelotl Oct 28, 2021
07fdeac
Add FIXMEs
ocelotl Oct 28, 2021
32b67e8
Add FIXMEs
ocelotl Oct 28, 2021
cb3ed60
Fix lint
ocelotl Oct 28, 2021
325e904
Add Aggregation to the metrics SDK
ocelotl Oct 21, 2021
ab5d753
lint fix wip
ocelotl Oct 25, 2021
26e103d
Fix lint
ocelotl Oct 25, 2021
49e82b6
Add proto to setup.cfg
ocelotl Oct 25, 2021
a58e1f9
Add timestamp for last value
ocelotl Oct 25, 2021
deb696f
Rename modules to be private
ocelotl Nov 2, 2021
904c7d9
Fix paths
ocelotl Nov 2, 2021
50e708a
Set value in concrete classes init
ocelotl Nov 10, 2021
b157bb7
Fix test
ocelotl Nov 11, 2021
3d5a779
Fix lint
ocelotl Nov 11, 2021
f1b9529
Remove temporalities
ocelotl Nov 11, 2021
46dad80
Use frozenset as key
ocelotl Nov 11, 2021
2c8e893
Test instruments
ocelotl Nov 11, 2021
2d9e0c3
Handle min, max and sum in explicit bucket histogram aggregator
ocelotl Nov 15, 2021
2f084f1
Add test for negative values
ocelotl Nov 15, 2021
641823c
Remove collect method from aggregations
ocelotl Nov 16, 2021
ed502c5
Add make_point_and_reset
ocelotl Nov 16, 2021
5f50e74
Remove add implementation
ocelotl Nov 16, 2021
f51cb8e
Remove _Synchronous
ocelotl Nov 16, 2021
c4196f7
Update opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py
ocelotl Nov 17, 2021
4c8454c
Requested fixes
ocelotl Nov 17, 2021
d8797bc
Remove NoneAggregation
ocelotl Nov 17, 2021
90f0ef8
Add changelog entry
ocelotl Nov 17, 2021
dd685f5
Fix tests
ocelotl Nov 17, 2021
b7f05b3
Fix boundaries
ocelotl Nov 17, 2021
8c1a8aa
More fixes
ocelotl Nov 17, 2021
7136925
Merge branch 'main' into issue_2229
ocelotl Nov 17, 2021
ec591ed
Update CHANGELOG.md
ocelotl Nov 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

- Adds Aggregation and instruments as part of Metrics SDK
([#2234](https://github.com/open-telemetry/opentelemetry-python/pull/2234))

## [1.7.1-0.26b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.7.0-0.26b0) - 2021-11-11


Expand Down
137 changes: 137 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod
from collections import OrderedDict
from logging import getLogger
from math import inf

from opentelemetry._metrics.instrument import _Monotonic
from opentelemetry.util._time import _time_ns

_logger = getLogger(__name__)


class Aggregation(ABC):
@property
def value(self):
return self._value # pylint: disable=no-member

@abstractmethod
def aggregate(self, value):
pass

@abstractmethod
def make_point_and_reset(self):
ocelotl marked this conversation as resolved.
Show resolved Hide resolved
"""
Atomically return a point for the current value of the metric and reset the internal state.
"""


class SumAggregation(Aggregation):
"""
This aggregation collects data for the SDK sum metric point.
"""

def __init__(self, instrument):
self._value = 0

def aggregate(self, value):
self._value = self._value + value

def make_point_and_reset(self):
pass


class LastValueAggregation(Aggregation):

"""
This aggregation collects data for the SDK sum metric point.
"""

def __init__(self, instrument):
self._value = None
self._timestamp = _time_ns()

def aggregate(self, value):
self._value = value
self._timestamp = _time_ns()

def make_point_and_reset(self):
pass


class ExplicitBucketHistogramAggregation(Aggregation):

"""
This aggregation collects data for the SDK sum metric point.
"""

def __init__(
self,
instrument,
*args,
boundaries=(0, 5, 10, 25, 50, 75, 100, 250, 500, 1000),
record_min_max=True,
ocelotl marked this conversation as resolved.
Show resolved Hide resolved
):
super().__init__()
ocelotl marked this conversation as resolved.
Show resolved Hide resolved
self._value = OrderedDict([(key, 0) for key in (*boundaries, inf)])
self._min = inf
self._max = -inf
self._sum = 0
self._instrument = instrument
self._record_min_max = record_min_max

@property
def min(self):
if not self._record_min_max:
_logger.warning("Min is not being recorded")

return self._min

@property
def max(self):
if not self._record_min_max:
_logger.warning("Max is not being recorded")

return self._max

@property
def sum(self):
if isinstance(self._instrument, _Monotonic):
return self._sum

_logger.warning(
"Sum is not filled out when the associated "
"instrument is not monotonic"
)
return None

def aggregate(self, value):
if self._record_min_max:
self._min = min(self._min, value)
self._max = max(self._max, value)

if isinstance(self._instrument, _Monotonic):
self._sum += value

for key in self._value.keys():

if value < key:
self._value[key] = self._value[key] + value

break

def make_point_and_reset(self):
pass
160 changes: 160 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/_metrics/instrument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=function-redefined
# pylint: disable=dangerous-default-value
# Classes in this module use dictionaries as default arguments. This is
# considered dangerous by pylint because the default dictionary is shared by
# all instances. Implementations of these classes must not make any change to
# this default dictionary in __init__.

from opentelemetry._metrics.instrument import (
Counter,
Histogram,
ObservableCounter,
ObservableGauge,
ObservableUpDownCounter,
UpDownCounter,
)
from opentelemetry.sdk._metrics.aggregation import (
ExplicitBucketHistogramAggregation,
LastValueAggregation,
SumAggregation,
)


class _Instrument:
def __init__(
self,
name,
unit="",
description="",
aggregation=None,
aggregation_config={},
):
self._attributes_aggregations = {}
self._aggregation = aggregation
self._aggregation_config = aggregation_config
aggregation(self, **aggregation_config)


class Counter(_Instrument, Counter):
def __init__(
self,
name,
unit="",
description="",
aggregation=SumAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)


class UpDownCounter(_Instrument, UpDownCounter):
def __init__(
self,
name,
unit="",
description="",
aggregation=SumAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)


class ObservableCounter(_Instrument, ObservableCounter):
def __init__(
self,
name,
callback,
unit="",
description="",
aggregation=SumAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)


class ObservableUpDownCounter(_Instrument, ObservableUpDownCounter):
def __init__(
self,
name,
callback,
unit="",
description="",
aggregation=SumAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)


class Histogram(_Instrument, Histogram):
def __init__(
self,
name,
unit="",
description="",
aggregation=ExplicitBucketHistogramAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)


class ObservableGauge(_Instrument, ObservableGauge):
def __init__(
self,
name,
callback,
unit="",
description="",
aggregation=LastValueAggregation,
aggregation_config={},
):
super().__init__(
name,
unit=unit,
description=description,
aggregation=aggregation,
aggregation_config=aggregation_config,
)
Loading