Explicit bucket histogram aggregation.
Uses :counters for thread-safe bucket increments and
ets:update_counter / ets:update_element for atomic
count, sum, min, and max updates.
ETS entry format:
{key, counters_ref, min, max, sum, count, start_time, reservoir_state}.
The eighth slot holds the exemplar reservoir state
(Otel.Metrics.Exemplar.Reservoir.AlignedHistogramBucket) so a
single ETS row carries everything collect/3 needs to emit a
datapoint with exemplars.
Cumulative-only — collect/3 returns running totals since
stream start. Delta temporality is not supported (minikube
hardcodes cumulative; spec metrics/sdk.md L1290-L1297 default).
Configuration parameters
Otel.Metrics.Meter.register_instrument/3 resolves
:boundaries from the instrument's advisory
:explicit_bucket_boundaries (when present).
| Key | Default | Description |
|---|---|---|
:boundaries | @default_boundaries (15 OTel-default buckets) | Bucket boundaries per metrics/sdk.md L660-L661 |
Spec metrics/sdk.md L662 also lists a RecordMinMax Stream
config knob; minikube has no Views so it is permanently on
and not exposed here. The encoder's min: nil / max: nil
path still exists for the brief concurrent-collect window
before the first measurement updates the ETS row.
Summary
Functions
@spec aggregate( metrics_tab :: :ets.table(), key :: term(), value :: number(), opts :: map() ) :: :ok
@spec collect( metrics_tab :: :ets.table(), stream_key :: String.t(), opts :: map() ) :: [Otel.Metrics.Aggregation.datapoint()]
@spec default_boundaries() :: [number()]
@spec offer_exemplar( metrics_tab :: :ets.table(), key :: term(), value :: number(), time :: non_neg_integer(), filtered_attrs :: %{required(String.t()) => term()}, ctx :: Otel.Ctx.t() ) :: :ok