# `Otel.Metrics.Exemplar.Reservoir.AlignedHistogramBucket`
[🔗](https://github.com/yangbancode/otel/blob/main/lib/otel/metrics/exemplar/reservoir/aligned_histogram_bucket.ex#L1)

A reservoir aligned with explicit histogram bucket boundaries.

Stores at most one exemplar per bucket. When a new measurement
falls into a bucket that already has an exemplar, the existing
one is replaced.

## Spec compliance

Spec `metrics/sdk.md` L1248-L1252 — *"This implementation
MUST store at most one measurement that falls within a
histogram bucket, and SHOULD use a uniformly-weighted
sampling algorithm based on the number of measurements the
bucket has seen so far ... Alternatively, the implementation
MAY instead keep the last seen measurement that falls within
a histogram bucket."*

We implement the **MAY alternative** (keep last-seen) — the
simpler of the two paths the spec offers. The MUST about at
most one exemplar per bucket is satisfied by the
`%{bucket_index => exemplar}` map shape.

# `primitive`

```elixir
@type primitive() ::
  String.t() | {:bytes, binary()} | boolean() | integer() | float() | nil
```

# `primitive_any`

```elixir
@type primitive_any() ::
  primitive() | [primitive_any()] | %{required(String.t()) =&gt; primitive_any()}
```

# `state`

```elixir
@type state() :: %{
  boundaries: [number()],
  exemplars: %{required(non_neg_integer()) =&gt; Otel.Metrics.Exemplar.t()}
}
```

# `collect`

```elixir
@spec collect(state :: state()) :: {[Otel.Metrics.Exemplar.t()], state()}
```

# `new`

```elixir
@spec new(opts :: map()) :: state()
```

# `offer`

```elixir
@spec offer(
  state :: state(),
  value :: number(),
  time :: non_neg_integer(),
  filtered_attributes :: %{required(String.t()) =&gt; primitive_any()},
  ctx :: Otel.Ctx.t()
) :: state()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
