# `ADK.Telemetry`
[🔗](https://github.com/zeroasterisk/adk-elixir/blob/main/lib/adk/telemetry.ex#L1)

Telemetry events for the ADK pipeline.

ADK emits `:telemetry` events at key execution points so you can attach
handlers for logging, metrics, tracing, or anything else.

## Events

All events follow the `[:adk, <component>, <stage>]` convention with
`:start`, `:stop`, and `:exception` suffixes (compatible with `:telemetry.span/3`).

### Agent Events — `[:adk, :agent, ...]`

* `[:adk, :agent, :start]` — fired when an agent begins execution
  * Measurements: `%{monotonic_time: integer(), system_time: integer()}`
  * Metadata: `%{agent_name: String.t(), session_id: term()}`

* `[:adk, :agent, :stop]` — fired when an agent completes
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start

* `[:adk, :agent, :exception]` — fired on agent crash
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start + `%{kind: atom(), reason: term(), stacktrace: list()}`

### LLM Events — `[:adk, :llm, ...]`

* `[:adk, :llm, :start]` — fired before an LLM call
  * Measurements: `%{monotonic_time: integer(), system_time: integer()}`
  * Metadata: `%{model: String.t(), agent_name: String.t()}`

* `[:adk, :llm, :stop]` — fired after an LLM call completes
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start

* `[:adk, :llm, :exception]` — fired on LLM call failure
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start + `%{kind: atom(), reason: term(), stacktrace: list()}`

### Tool Events — `[:adk, :tool, ...]`

* `[:adk, :tool, :start]` — fired before a tool executes
  * Measurements: `%{monotonic_time: integer(), system_time: integer()}`
  * Metadata: `%{tool_name: String.t(), agent_name: String.t()}`

* `[:adk, :tool, :stop]` — fired after a tool completes
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start

* `[:adk, :tool, :exception]` — fired on tool crash
  * Measurements: `%{duration: integer(), monotonic_time: integer()}`
  * Metadata: same as start + `%{kind: atom(), reason: term(), stacktrace: list()}`

## Attaching Handlers

    :telemetry.attach_many(
      "my-adk-handler",
      ADK.Telemetry.events(),
      &MyHandler.handle_event/4,
      nil
    )

## OpenTelemetry Integration

When the full `:opentelemetry` SDK is loaded, `span/3` will additionally create
OpenTelemetry spans, bridging `:telemetry` events into distributed traces.
No configuration needed — it auto-detects.

# `events`

```elixir
@spec events() :: [[atom()]]
```

Returns all event names for use with `:telemetry.attach_many/4`.

# `span`

```elixir
@spec span([atom()], map(), (-&gt; term())) :: term()
```

Execute `fun` wrapped in a `:telemetry.span/3` call.

`event_prefix` should be `[:adk, :agent]`, `[:adk, :llm]`, or `[:adk, :tool]`.
`metadata` is passed through to all events. `fun` must return `{result, extra_measurements}`
or just `result` (in which case extra measurements default to `%{}`).

When `opentelemetry_api` is available, an OTel span is also created.

---

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