# `Ascii.Telemetry`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/telemetry.ex#L2)

Your app's `:telemetry` events as live data for the pieces: a process
that keeps a reading of each metric a sample at a time, for a
sparkline's series, a gauge's needle or a progress bar.

    children = [
      {Ascii.Telemetry,
       name: MyApp.Readings,
       metrics: [
         Telemetry.Metrics.last_value("vm.memory.total", unit: {:byte, :megabyte}),
         Telemetry.Metrics.counter("phoenix.endpoint.stop.duration", reporter_options: [label: "requests"]),
         Telemetry.Metrics.summary("my_app.repo.query.total_time", unit: {:native, :millisecond})
       ]}
    ]

    # in a LiveView
    if connected?(socket), do: Ascii.Telemetry.subscribe(MyApp.Readings)

    def handle_info({:ascii_telemetry, _feed, readings}, socket),
      do: {:noreply, assign(socket, history: Ascii.Telemetry.sparkline(readings))}

    <Ascii.Phoenix.live_player id="history" piece="sparkline" options={@history} />

Or have it feed players itself, each sample:

    {Ascii.Telemetry, metrics: metrics, players: [{MyApp.History, &Ascii.Telemetry.sparkline/1}]}

## Metrics

`Telemetry.Metrics` definitions, as for any reporter (the
`telemetry_metrics` package; it need not be a dependency of this
library), or maps of the same: `%{name: "db", event: [:my_app, :repo,
:query], measurement: :total_time, kind: :summary, unit: "ms"}`. Each
sample, every `:every` milliseconds, gives each metric one reading:

  * `last_value` - its latest measurement (kept until another comes);
  * `counter` - how many events came;
  * `sum` - their measurements added up;
  * `summary`, `distribution` - their mean, or nothing if none came.

A metric's label is its `reporter_options[:label]`, else its name's last
part but one, as `memory` for `vm.memory.total`; its unit is the one it
converts to.

## Options

  * `:metrics` - the metrics (required).
  * `:every` - milliseconds a sample (default 1000).
  * `:window` - samples kept of each metric (default 120).
  * `:players` - `{player, fun}` pairs: each sample, `fun` turns the
    readings into options for the player (`Ascii.Player.set_options/2`).
  * `:name` - to register the process.

Handlers run in the processes that emit the events, so each is a
message to this process and no more. They are detached when it stops.
Only available when `telemetry` is a dependency (Phoenix brings it).

# `readings`

```elixir
@type readings() :: [%{label: String.t(), unit: String.t(), values: [number()]}]
```

A metric's readings, oldest first, by its label, with its unit.

# `gauge`

```elixir
@spec gauge(
  readings :: readings(),
  opts :: [label: String.t(), min: number(), max: number()]
) :: map()
```

Options for `gauge`: the latest reading of the metric `label` (the first,
if not given), its label and unit; `:min` and `:max` for the dial.

# `readings`

```elixir
@spec readings(feed :: GenServer.server()) :: readings()
```

The readings so far.

# `sparkline`

```elixir
@spec sparkline(
  readings :: readings(),
  opts :: [only: [String.t()], every: pos_integer()]
) :: map()
```

Options for `sparkline`: a series a metric (the first five; `:only`
picks by label), and its rate, samples a second.

# `start_link`

```elixir
@spec start_link(opts :: keyword()) :: GenServer.on_start()
```

Starts a feed; see the module docs for the options.

# `subscribe`

```elixir
@spec subscribe(feed :: GenServer.server()) :: :ok
```

Sends the calling process `{:ascii_telemetry, feed, readings}` after
every sample, until it exits.

---

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