Skip to content

Commit 80593c2

Browse files
lseguyemdnetoxrmx
authored
opentelemetry-sdk: fix explicit histogram aggregation to handle multiple explicit bucket advisories (#4521)
* opentelemetry-sdk: fix explicit aggregation with multiple histogram explicit buckets advisory * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Emídio Neto <[email protected]> * Update opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py Co-authored-by: Riccardo Magliocchetti <[email protected]> * Add integration test for default bucket boundaries * Renaming variable --------- Co-authored-by: Emídio Neto <[email protected]> Co-authored-by: Riccardo Magliocchetti <[email protected]>
1 parent 48fc3bf commit 80593c2

File tree

3 files changed

+85
-6
lines changed

3 files changed

+85
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
([#4494](https://github.com/open-telemetry/opentelemetry-python/pull/4494))
1818
- Improve CI by cancelling stale runs and setting timeouts
1919
([#4498](https://github.com/open-telemetry/opentelemetry-python/pull/4498))
20+
- Fix ExplicitBucketHistogramAggregation to handle multiple explicit bucket boundaries advisories
21+
([#4521](https://github.com/open-telemetry/opentelemetry-python/pull/4521))
2022

2123
## Version 1.31.0/0.52b0 (2025-03-12)
2224

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/aggregation.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,18 +1387,17 @@ def _create_aggregation(
13871387
AggregationTemporality.CUMULATIVE
13881388
)
13891389

1390-
if self._boundaries is None:
1391-
self._boundaries = (
1392-
instrument._advisory.explicit_bucket_boundaries
1393-
or _DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES
1394-
)
1390+
if self._boundaries is not None:
1391+
boundaries = self._boundaries
1392+
else:
1393+
boundaries = instrument._advisory.explicit_bucket_boundaries
13951394

13961395
return _ExplicitBucketHistogramAggregation(
13971396
attributes,
13981397
instrument_aggregation_temporality,
13991398
start_time_unix_nano,
14001399
reservoir_factory(_ExplicitBucketHistogramAggregation),
1401-
self._boundaries,
1400+
boundaries,
14021401
self._record_min_max,
14031402
)
14041403

opentelemetry-sdk/tests/metrics/integration_test/test_histogram_advisory_explicit_buckets.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
from unittest import TestCase
1616

1717
from opentelemetry.sdk.metrics import MeterProvider
18+
from opentelemetry.sdk.metrics._internal.aggregation import (
19+
_DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES,
20+
)
1821
from opentelemetry.sdk.metrics._internal.instrument import Histogram
1922
from opentelemetry.sdk.metrics.export import InMemoryMetricReader
2023
from opentelemetry.sdk.metrics.view import (
@@ -164,3 +167,78 @@ def test_explicit_aggregation(self):
164167
self.assertEqual(
165168
metric.data.data_points[0].explicit_bounds, (1.0, 2.0, 3.0)
166169
)
170+
171+
def test_explicit_aggregation_multiple_histograms(self):
172+
reader = InMemoryMetricReader(
173+
preferred_aggregation={
174+
Histogram: ExplicitBucketHistogramAggregation()
175+
}
176+
)
177+
meter_provider = MeterProvider(
178+
metric_readers=[reader],
179+
)
180+
meter = meter_provider.get_meter("testmeter")
181+
182+
histogram1 = meter.create_histogram(
183+
"testhistogram1",
184+
explicit_bucket_boundaries_advisory=[1.0, 2.0, 3.0],
185+
)
186+
histogram1.record(1, {"label": "value"})
187+
histogram1.record(2, {"label": "value"})
188+
histogram1.record(3, {"label": "value"})
189+
190+
histogram2 = meter.create_histogram(
191+
"testhistogram2",
192+
explicit_bucket_boundaries_advisory=[4.0, 5.0, 6.0],
193+
)
194+
histogram2.record(4, {"label": "value"})
195+
histogram2.record(5, {"label": "value"})
196+
histogram2.record(6, {"label": "value"})
197+
198+
metrics = reader.get_metrics_data()
199+
self.assertEqual(len(metrics.resource_metrics), 1)
200+
self.assertEqual(len(metrics.resource_metrics[0].scope_metrics), 1)
201+
self.assertEqual(
202+
len(metrics.resource_metrics[0].scope_metrics[0].metrics), 2
203+
)
204+
metric1 = metrics.resource_metrics[0].scope_metrics[0].metrics[0]
205+
self.assertEqual(metric1.name, "testhistogram1")
206+
self.assertEqual(
207+
metric1.data.data_points[0].explicit_bounds, (1.0, 2.0, 3.0)
208+
)
209+
metric2 = metrics.resource_metrics[0].scope_metrics[0].metrics[1]
210+
self.assertEqual(metric2.name, "testhistogram2")
211+
self.assertEqual(
212+
metric2.data.data_points[0].explicit_bounds, (4.0, 5.0, 6.0)
213+
)
214+
215+
def test_explicit_aggregation_default_boundaries(self):
216+
reader = InMemoryMetricReader(
217+
preferred_aggregation={
218+
Histogram: ExplicitBucketHistogramAggregation()
219+
}
220+
)
221+
meter_provider = MeterProvider(
222+
metric_readers=[reader],
223+
)
224+
meter = meter_provider.get_meter("testmeter")
225+
226+
histogram = meter.create_histogram(
227+
"testhistogram",
228+
)
229+
histogram.record(1, {"label": "value"})
230+
histogram.record(2, {"label": "value"})
231+
histogram.record(3, {"label": "value"})
232+
233+
metrics = reader.get_metrics_data()
234+
self.assertEqual(len(metrics.resource_metrics), 1)
235+
self.assertEqual(len(metrics.resource_metrics[0].scope_metrics), 1)
236+
self.assertEqual(
237+
len(metrics.resource_metrics[0].scope_metrics[0].metrics), 1
238+
)
239+
metric = metrics.resource_metrics[0].scope_metrics[0].metrics[0]
240+
self.assertEqual(metric.name, "testhistogram")
241+
self.assertEqual(
242+
metric.data.data_points[0].explicit_bounds,
243+
_DEFAULT_EXPLICIT_BUCKET_HISTOGRAM_AGGREGATION_BOUNDARIES,
244+
)

0 commit comments

Comments
 (0)