Skip to content

Commit

Permalink
Update sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
xrmx committed Dec 17, 2024
1 parent b676189 commit 42b0b0c
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
# 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.

import weakref
from atexit import register, unregister
from collections.abc import Sequence
from logging import getLogger
from os import environ
from threading import Lock
from time import time_ns
from typing import Optional, Sequence
from typing import Optional

# This kind of import is needed to avoid Sphinx errors.
import opentelemetry.sdk.metrics
Expand Down Expand Up @@ -63,7 +65,7 @@
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util.instrumentation import InstrumentationScope
from opentelemetry.util._once import Once
from opentelemetry.util.types import Attributes
from opentelemetry.util.types import Attributes, MetricsInstrumentAdvisory

_logger = getLogger(__name__)

Expand Down Expand Up @@ -196,7 +198,29 @@ def create_observable_counter(
self._instrument_id_instrument[instrument_id] = instrument
return instrument

def create_histogram(self, name, unit="", description="") -> APIHistogram:
def create_histogram(
self,
name: str,
unit: str = "",
description: str = "",
advisory: MetricsInstrumentAdvisory = None,
) -> APIHistogram:
if advisory is not None:
raise_error = False
try:
boundaries = advisory["ExplicitBucketBoundaries"]
raise_error = not (
boundaries
and all(isinstance(e, (int, float)) for e in boundaries)
)
except (KeyError, TypeError):
raise_error = True

if raise_error:
raise ValueError(
"Advisory must be a dict with ExplicitBucketBoundaries key containing a sequence of numbers"
)

(
is_instrument_registered,
instrument_id,
Expand All @@ -223,6 +247,7 @@ def create_histogram(self, name, unit="", description="") -> APIHistogram:
self._measurement_consumer,
unit,
description,
advisory,
)
with self._instrument_id_instrument_lock:
self._instrument_id_instrument[instrument_id] = instrument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,32 +437,40 @@ def collect(
)


_DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES: Sequence[float] = (
0.0,
5.0,
10.0,
25.0,
50.0,
75.0,
100.0,
250.0,
500.0,
750.0,
1000.0,
2500.0,
5000.0,
7500.0,
10000.0,
)


class _ExplicitBucketHistogramAggregation(_Aggregation[HistogramPoint]):
def __init__(
self,
attributes: Attributes,
instrument_aggregation_temporality: AggregationTemporality,
start_time_unix_nano: int,
reservoir_builder: ExemplarReservoirBuilder,
boundaries: Sequence[float] = (
0.0,
5.0,
10.0,
25.0,
50.0,
75.0,
100.0,
250.0,
500.0,
750.0,
1000.0,
2500.0,
5000.0,
7500.0,
10000.0,
),
boundaries: Optional[Sequence[float]] = None,
record_min_max: bool = True,
):
if boundaries is None:
boundaries = (
_DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES
)

super().__init__(
attributes,
reservoir_builder=partial(
Expand Down Expand Up @@ -1268,6 +1276,11 @@ def _create_aggregation(
)

if isinstance(instrument, Histogram):
boundaries: Optional[Sequence[float]] = (
instrument.advisory.get("ExplicitBucketBoundaries")
if instrument.advisory is not None
else None
)
return _ExplicitBucketHistogramAggregation(
attributes,
reservoir_builder=reservoir_factory(
Expand All @@ -1276,6 +1289,7 @@ def _create_aggregation(
instrument_aggregation_temporality=(
AggregationTemporality.DELTA
),
boundaries=boundaries,
start_time_unix_nano=start_time_unix_nano,
)

Expand Down Expand Up @@ -1347,25 +1361,13 @@ class ExplicitBucketHistogramAggregation(Aggregation):

def __init__(
self,
boundaries: Sequence[float] = (
0.0,
5.0,
10.0,
25.0,
50.0,
75.0,
100.0,
250.0,
500.0,
750.0,
1000.0,
2500.0,
5000.0,
7500.0,
10000.0,
),
boundaries: Optional[Sequence[float]] = None,
record_min_max: bool = True,
) -> None:
if boundaries is None:
boundaries = (
_DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES
)
self._boundaries = boundaries
self._record_min_max = record_min_max

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from opentelemetry.metrics._internal.instrument import CallbackOptions
from opentelemetry.sdk.metrics._internal.measurement import Measurement
from opentelemetry.sdk.util.instrumentation import InstrumentationScope
from opentelemetry.util.types import MetricsInstrumentAdvisory

_logger = getLogger(__name__)

Expand Down Expand Up @@ -219,6 +220,24 @@ def __new__(cls, *args, **kwargs):


class Histogram(_Synchronous, APIHistogram):
def __init__(
self,
name: str,
instrumentation_scope: InstrumentationScope,
measurement_consumer: "opentelemetry.sdk.metrics.MeasurementConsumer",
unit: str = "",
description: str = "",
advisory: MetricsInstrumentAdvisory = None,
):
super().__init__(
name,
unit=unit,
description=description,
instrumentation_scope=instrumentation_scope,
measurement_consumer=measurement_consumer,
)
self.advisory = advisory

def __new__(cls, *args, **kwargs):
if cls is Histogram:
raise TypeError("Histogram must be instantiated via a meter.")
Expand Down
17 changes: 17 additions & 0 deletions opentelemetry-sdk/tests/metrics/test_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# pylint: disable=protected-access

from math import inf
from random import randint
from time import sleep, time_ns
from typing import Union
from unittest import TestCase
Expand Down Expand Up @@ -628,6 +629,22 @@ def test_histogram(self):
)
self.assertIsInstance(aggregation, _ExplicitBucketHistogramAggregation)

def test_histogram_with_advisory(self):
boundaries = [randint(0, 1000)]
aggregation = self.default_aggregation._create_aggregation(
_Histogram(
"name",
Mock(),
Mock(),
advisory={"ExplicitBucketBoundaries": boundaries},
),
Mock(),
_default_reservoir_factory,
0,
)
self.assertIsInstance(aggregation, _ExplicitBucketHistogramAggregation)
self.assertEqual(aggregation._boundaries, tuple(boundaries))

def test_gauge(self):
aggregation = self.default_aggregation._create_aggregation(
_Gauge(
Expand Down
32 changes: 32 additions & 0 deletions opentelemetry-sdk/tests/metrics/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,38 @@ def test_create_histogram(self):
self.assertIsInstance(histogram, Histogram)
self.assertEqual(histogram.name, "name")

def test_create_histogram_with_advisory(self):
histogram = self.meter.create_histogram(
"name",
unit="unit",
description="description",
advisory={"ExplicitBucketBoundaries": [0, 1, 2]},
)

self.assertIsInstance(histogram, Histogram)
self.assertEqual(histogram.name, "name")
self.assertEqual(
histogram.advisory, {"ExplicitBucketBoundaries": [0, 1, 2]}
)

def test_create_histogram_advisory_validation(self):
advisories = [
{"ExplicitBucketBoundaries": None},
{"ExplicitBucketBoundaries": []},
{},
[],
{"ExplicitBucketBoundaries": [1, 2.0, "3"]},
]
for advisory in advisories:
with self.subTest(advisory=advisory):
with self.assertRaises(ValueError):
self.meter.create_histogram(
"name",
unit="unit",
description="description",
advisory=advisory,
)

def test_create_observable_gauge(self):
observable_gauge = self.meter.create_observable_gauge(
"name", callbacks=[Mock()], unit="unit", description="description"
Expand Down

0 comments on commit 42b0b0c

Please sign in to comment.