Telemetry handler that routes agent-side events
([:raxol, :agent, :policy, :*] and
[:raxol, :agent, :sandbox, :denied]) into a
Raxol.Agent.ThreadLog adapter as durable audit entries.
How it works
attach/3 calls :telemetry.attach_many/4 for the agent-side
event family, passing the ThreadLog adapter tuple and the agent's
thread_id in the handler config. Every matching event is
translated into one ThreadLog.append/5 call with
kind: :policy_result (for policy events) or
kind: :sandbox_deny (for sandbox denials).
Detach via detach/1 (e.g. in the agent's terminate/2).
Wiring
Consumers typically call this at agent startup once
agent_module.thread_log/0 resolves to a non-nil adapter:
adapter = Raxol.Agent.ThreadLog.normalize(MyAgent.thread_log())
handler_id = "raxol_agent_thread_log_router_#{agent_id}"
Raxol.Agent.ThreadLogRouter.attach(handler_id, adapter, agent_id)
# ... later, on terminate
Raxol.Agent.ThreadLogRouter.detach(handler_id)When adapter is nil, attach/3 returns :ok without
attaching, so callers don't need to branch.
Event mapping
| Telemetry event | ThreadLog kind | Payload |
|---|---|---|
[:raxol, :agent, :policy, :cache_hit] | :policy_result | %{policy: :cache, decision: :hit, key, params} |
[:raxol, :agent, :policy, :cache_miss] | :policy_result | %{policy: :cache, decision: :miss, key, params} |
[:raxol, :agent, :policy, :retry_attempt] | :policy_result | %{policy: :retry, decision: :attempt, attempt, reason, backoff_ms} |
[:raxol, :agent, :policy, :retry_exhausted] | :policy_result | %{policy: :retry, decision: :exhausted, attempt, reason} |
[:raxol, :agent, :policy, :timeout] | :policy_result | %{policy: :timeout, decision: :fired, wall_ms} |
[:raxol, :agent, :policy, :applied] | :policy_result | %{policy: :applied, policy_kinds, outcome} |
[:raxol, :agent, :sandbox, :denied] | :sandbox_deny | %{action, reason} |
All payloads include a metadata map mirroring the telemetry
event's metadata (minus agent_id/agent_module which are
redundant with the thread_id).
Summary
Functions
Attach a telemetry handler that routes agent-side events to the
given ThreadLog adapter under thread_id.
Detach a previously-attached handler. Idempotent.
Functions
@spec attach( binary(), Raxol.Agent.ThreadLog.config() | {module(), Raxol.Agent.ThreadLog.config()} | nil, binary() ) :: :ok | {:error, term()}
Attach a telemetry handler that routes agent-side events to the
given ThreadLog adapter under thread_id.
adapter is the {module, config} tuple (or bare module) as
returned by Raxol.Agent.ThreadLog.normalize/1. Pass nil to
no-op (useful when the agent declares no thread_log/0).
Returns :ok on success or when adapter is nil. Returns
{:error, :already_exists} if handler_id is already attached.
@spec detach(binary()) :: :ok
Detach a previously-attached handler. Idempotent.