open-telemetry / open-telemetry/opentelemetry-cpp
Define and enforce a runtime minimum scale for Base2ExponentialHistogramAggregation
@ThomsonTan is already working on this.
Since Aug 3, 2026.
- Dominant language
- C++
- Stars
- 1.4k
- Forks
- 632
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 75
Description
Describe your environment
- Repository revision: PR #4324
- Reproduced on Windows with MSVC 19.44 using a CMake/Ninja Release build
- The runtime scale behavior predates PR #4324; that PR only exposed it during review
Steps to reproduce
Configure a base2 exponential histogram at the lowest currently accepted max_scale_ and max_size_, then record values at both ends of the finite double range:
using namespace opentelemetry::sdk::metrics;
Base2ExponentialHistogramAggregationConfig config;
config.max_scale_ = kMaxScaleMin; // -10
config.max_size_ = kMaxSizeMin; // 2
Base2ExponentialHistogramAggregation aggregation{&config};
aggregation.Aggregate((std::numeric_limits<double>::denorm_min)());
aggregation.Aggregate((std::numeric_limits<double>::max)());
const auto point =
opentelemetry::nostd::get<Base2ExponentialHistogramPointData>(aggregation.ToPoint());
EXPECT_GE(point.scale_, kMaxScaleMin);
The current implementation accepts -10 as the configured maximum scale in aggregation_config.h, but automatic scale reduction never applies a lower bound.
What is the expected behavior?
The aggregation should define and enforce a reasonable runtime minimum scale for every automatic reduction path.
If -10 is selected as the C++ SDK's runtime minimum, point.scale_ should never become less than -10. When an input range still cannot fit within max_size_ at that floor, the implementation should apply an explicit, documented policy while preserving all recorded counts.
What is the actual behavior?
The reproduction produces:
point.scale_ == -11
At scale -10, denorm_min() and max() map to bucket indices -2 and 0. Their three-bucket span exceeds max_size_ == 2, so GetScaleReduction() requests one additional reduction. Base2ExponentialHistogramAggregation::Downscale() then subtracts that reduction without consulting any runtime floor:
const uint32_t scale_reduction =
GetScaleReduction(start_index, end_index, point_data_.max_buckets_);
Downscale(scale_reduction);
// ...
point_data_.scale_ -= static_cast<int32_t>(by);
Additional context
Related:
Tip: React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.