:telemetry events emitted around every provider call.
A library whose job is calling billed APIs has to be measurable: latency, token spend, failure rate, and tool-loop depth are operational facts, not debugging trivia. Attaching a handler is the supported way to get them - nothing here logs on your behalf.
Events
| Event | Measurements | Metadata |
|---|---|---|
[:ex_agent, :chat, :start] | :system_time | :provider, :model, :message_count, :streaming? |
[:ex_agent, :chat, :stop] | :duration, plus :input_tokens, :output_tokens, :total_tokens when reported | :provider, :model, :result, :streaming? |
[:ex_agent, :chat, :exception] | :duration | :provider, :model, :kind, :reason, :stacktrace |
[:ex_agent, :embed, :start] | :system_time | :provider, :input_count |
[:ex_agent, :embed, :stop] | :duration, :input_tokens, :total_tokens | :provider, :model, :result |
[:ex_agent, :tool, :stop] | :duration | :tool, :result |
:result is :ok, :tool_calls, or :error. On :error the metadata also
carries :error_type and :retryable? from ExAgent.Error, which is what a
retry-rate dashboard is actually built on.
Example
:telemetry.attach(
"ex-agent-cost",
[:ex_agent, :chat, :stop],
fn _event, measurements, metadata, _config ->
MyApp.Metrics.record(metadata.model, measurements[:total_tokens] || 0)
end,
nil
):telemetry is a hard dependency but a tiny one, and emitting with no handler
attached costs a single ETS lookup.
Summary
Functions
Runs fun, emitting :start/:stop/:exception events under [:ex_agent | name].