Every wait performed by WaitForIt is instrumented with :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

:telemetry.attach_many(
  "wait-for-it-logger",
  [
    [:wait_for_it, :wait, :stop],
    [:wait_for_it, :wait, :exception]
  ],
  &MyApp.WaitForItHandler.handle_event/4,
  nil
)
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 for dashboards and reporters. For example:

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

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