# `Sys.Mon.Sampler`
[🔗](https://github.com/harmont-dev/hyper/blob/main/lib/sys/mon/sampler.ex#L1)

Behaviour for a single soft-metric probe.

A sampler is the I/O-bearing source of instantaneous readings driven by
`Sys.Mon.Server`. It may carry private state between samples (e.g. the previous
`/proc/stat` snapshot needed to turn cumulative counters into a rate).

The sampler module *fully describes* its monitor: alongside the readings it
declares its own schedule (`period/0`, `tau/0`), so
`Sys.Mon.Server.start_link(SamplerModule)` needs nothing else.

A reading is whatever domain value the sampler chooses - a number or any
`Unit.Quantity` (a `Unit.Information` for memory, a `Unit.Bandwidth` for
throughput, a bare `Float` fraction for CPU) - so `Sys.Mon.Server` can
low-pass-filter it and it flows out of the monitor unchanged, with no float-only
bottleneck.

# `private`

```elixir
@type private() :: term()
```

Sampler-private carry-over state.

# `reading`

```elixir
@type reading() :: number() | Unit.Quantity.t()
```

An instantaneous reading: a number or any `Unit.Quantity`.

# `init`

```elixir
@callback init() :: {:ok, private()} | {:error, term()}
```

Initialize sampler-private state.

# `period`

```elixir
@callback period() :: Unit.Time.t()
```

How often to sample.

# `sample`

```elixir
@callback sample(private()) ::
  {:ok, reading(), private()} | {:skip, private()} | {:error, term()}
```

Produce the next reading.

`:skip` means a reading could not yet be formed (e.g. no baseline for a rate),
and the filter is left untouched. `:error` is a transient failure to be logged.

# `tau`

```elixir
@callback tau() :: Unit.Time.t()
```

The low-pass filter time constant (the smoothing window, independent of `period/0`).

---

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