# Telemetry

Every wait performed by WaitForIt is instrumented with [`:telemetry`](https://hexdocs.pm/telemetry)
events, so you can observe waiting in production: how long waits take, how many evaluations they
need, and how often they time out.

## Events

WaitForIt emits a standard telemetry span under the `[:wait_for_it, :wait]` prefix.

### `[:wait_for_it, :wait, :start]`

Emitted when a wait begins.

- **Measurements:** `%{system_time, monotonic_time}`
- **Metadata:** `%{wait_type, timeout, interval, signal, env}`

### `[:wait_for_it, :wait, :stop]`

Emitted when a wait finishes — whether the waiting condition was met or the wait timed out.

- **Measurements:** `%{duration, evaluations}`
  - `duration` is in native time units (use `System.convert_time_unit/3` to convert).
  - `evaluations` is the number of times the waitable expression was evaluated.
- **Metadata:** `%{wait_type, timeout, interval, signal, env, result, last_value}`
  - `result` is `:matched` (the condition was met) or `:timeout`.

### `[:wait_for_it, :wait, :exception]`

Emitted only if evaluating the waitable expression raises, throws, or exits unexpectedly. A
timeout is **not** an exception: it is reported as a `:stop` event with `result: :timeout`.

- **Measurements:** `%{duration}`
- **Metadata:** `%{wait_type, timeout, interval, signal, env, kind, reason, stacktrace}`

## Attaching a handler

```elixir
:telemetry.attach_many(
  "wait-for-it-logger",
  [
    [:wait_for_it, :wait, :stop],
    [:wait_for_it, :wait, :exception]
  ],
  &MyApp.WaitForItHandler.handle_event/4,
  nil
)
```

```elixir
defmodule MyApp.WaitForItHandler do
  require Logger

  def handle_event([:wait_for_it, :wait, :stop], measurements, metadata, _config) do
    ms = System.convert_time_unit(measurements.duration, :native, :millisecond)

    Logger.info(
      "WaitForIt #{metadata.wait_type} #{metadata.result} after #{ms}ms " <>
        "(#{measurements.evaluations} evaluations)"
    )
  end

  def handle_event([:wait_for_it, :wait, :exception], _measurements, metadata, _config) do
    Logger.error("WaitForIt #{metadata.wait_type} crashed: #{inspect(metadata.reason)}")
  end
end
```

## Using `Telemetry.Metrics`

The events compose with [`Telemetry.Metrics`](https://hexdocs.pm/telemetry_metrics) for
dashboards and reporters. For example:

```elixir
import Telemetry.Metrics

[
  # Distribution of wait durations, tagged by the form of waiting and the outcome.
  distribution("wait_for_it.wait.stop.duration",
    unit: {:native, :millisecond},
    tags: [:wait_type, :result]
  ),
  # How many evaluations waits needed — useful for tuning :interval.
  summary("wait_for_it.wait.stop.evaluations", tags: [:wait_type]),
  # Count of timeouts vs matches.
  counter("wait_for_it.wait.stop.duration", tags: [:wait_type, :result])
]
```

Because metadata includes `result`, you can alert on a rising rate of `result: :timeout` for a
given `wait_type` — an early signal that a dependency is getting slow.

---

**Previous:** [Recipes](recipes.md)

That's the end of the guides. See the `WaitForIt` module for the complete API reference.
