# `ExAthena.Telemetry`
[🔗](https://github.com/udin-io/ex_athena/blob/v0.7.1/lib/ex_athena/telemetry.ex#L1)

Telemetry emission for ExAthena, shaped to the OpenTelemetry GenAI
semantic conventions so consumers can plug directly into OTel without
a translation layer.

## Events

All events use the standard `:telemetry` library — attach handlers with
`:telemetry.attach/4` or use `opentelemetry_telemetry` for OTel.

  * `[:ex_athena, :loop, :start]` — a `Loop.run/2` began.
  * `[:ex_athena, :loop, :stop]` — the loop terminated. Measurements
    include `:duration_ms`, `:iterations`, `:tool_calls_made`,
    `:cost_usd`. Metadata includes the full `%Result{}`.
  * `[:ex_athena, :loop, :exception]` — an unhandled error bubbled out.
  * `[:ex_athena, :chat, :start]` — a single provider call began.
  * `[:ex_athena, :chat, :stop]` — the provider call returned.
    Measurements include `:duration_ms`, `:input_tokens`,
    `:output_tokens`, `:total_tokens`.
  * `[:ex_athena, :tool, :start]` — a tool invocation began.
  * `[:ex_athena, :tool, :stop]` — the tool invocation finished.
    Measurements include `:duration_ms`. Metadata includes `:is_error`.
  * `[:ex_athena, :compaction, :stop]` — a compaction pass completed.
    Measurements include `:before_tokens`, `:after_tokens`,
    `:dropped_count`.
  * `[:ex_athena, :subagent, :spawn]` / `[:ex_athena, :subagent, :stop]`
    — a subagent was spawned / returned.
  * `[:ex_athena, :structured_retry]` — a structured-output repair
    attempt fired. Measurements include `:attempt`.

## GenAI semconv metadata

Event metadata uses GenAI semantic-convention attribute keys where they
apply. The key Elixir-atom form mirrors the OTel dotted-path form:

  * `:gen_ai_operation_name` — `"chat"`, `"invoke_agent"`, `"execute_tool"`
  * `:gen_ai_provider_name` — e.g. `"openai"`, `"anthropic"`, `"ollama"`
  * `:gen_ai_request_model` — the model requested
  * `:gen_ai_response_model` — the model the response identified as
  * `:gen_ai_agent_id` — an optional agent identifier
  * `:gen_ai_conversation_id` — stable per-session identifier
  * `:gen_ai_usage_input_tokens`, `:gen_ai_usage_output_tokens`
  * `:gen_ai_tool_name`, `:gen_ai_tool_call_id`
  * `:gen_ai_response_finish_reasons` — list, e.g. `[:stop]`

Consumers bridging to OTel should translate these atoms to the dotted
OTel names (`gen_ai.operation.name`, etc.); `opentelemetry_telemetry`
handles this automatically if you point it at the events above.

# `event`

```elixir
@spec event([atom()], map(), map()) :: :ok
```

Emit a single telemetry event (no timing). Convenience for discrete
events like `:structured_retry`, `:subagent_spawn`, `:compaction_stop`.

# `genai_meta`

```elixir
@spec genai_meta(keyword()) :: map()
```

Build a GenAI-semconv-shaped metadata map from common loop inputs.

Use this to produce a consistent metadata surface across emitters.

# `span`

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

Execute `fun/0` inside a `[:ex_athena, name, ...]` span.

Emits `:start`, then `:stop` (or `:exception` on raise) with GenAI
metadata merged in. Returns `fun`'s result unchanged.

---

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