ExAthena.Telemetry (ExAthena v0.4.6)

Copy Markdown View Source

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.

Summary

Functions

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

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

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

Functions

event(name, measurements \\ %{}, meta \\ %{})

@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(opts)

@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(prefix, meta \\ %{}, fun)

@spec span([atom()], map(), (-> 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.