OpenTelemetry-style span and event emission for the BeamAgent SDK.
All five backend session handlers emit telemetry events via this module so that
consuming applications can attach handlers once and observe every backend
uniformly. No OTLP export or collector is built in — this module follows the
Erlang/OTP :telemetry convention: the library emits events, applications
handle them.
Optional dependency
The :telemetry library is an optional dependency. When present, events
are emitted via :telemetry.execute/3. When absent, all emission is a silent
no-op with zero overhead. To enable telemetry, add {:telemetry, "~> 1.3"} to
your application's deps in mix.exs and ensure the :telemetry application
is started.
When to use directly vs through BeamAgent
Backends call this module internally during session operation. Use it directly only when implementing a custom backend adapter or adding instrumentation to a session handler.
Event namespace
All events are published under the [:beam_agent, ...] prefix. The agent
parameter (an atom such as :claude or :codex) becomes the second element of
the event name list:
[:beam_agent, :claude, :query, :start]
[:beam_agent, :claude, :query, :stop]
[:beam_agent, :claude, :query, :exception]
[:beam_agent, :session, :state_change] # always at this fixed path
[:beam_agent, :run, :state_change] # canonical run lifecycle
[:beam_agent, :buffer, :overflow] # always at this fixed pathSpan lifecycle example
start_time = BeamAgent.Telemetry.span_start(:claude, :query, %{session_id: id})
# ... do work ...
BeamAgent.Telemetry.span_stop(:claude, :query, start_time)Attaching handlers
Use the standard :telemetry.attach/4 or :telemetry.attach_many/4 call in
your application startup:
:telemetry.attach_many(
:my_handler,
[
[:beam_agent, :claude, :query, :start],
[:beam_agent, :claude, :query, :stop]
],
&MyTelemetryHandler.handle/4,
[]
)See the :telemetry library documentation for handler function signature details.
Summary
Functions
Emit a buffer overflow warning when accumulated transport data exceeds the limit.
Emit a span exception event when a unit of work fails.
Emit a span exception event with additional metadata.
Emit a span start event and return a monotonic start time.
Emit a span stop event, computing duration from the start time.
Emit a span stop event with additional metadata.
Emit a state change event for a gen_statem transition.
Emit a state change event for a non-session BeamAgent domain.
Functions
@spec buffer_overflow(pos_integer(), pos_integer()) :: :ok
Emit a buffer overflow warning when accumulated transport data exceeds the limit.
The event is published at the fixed path [:beam_agent, :buffer, :overflow].
This event fires when the session engine's inbound buffer grows beyond the
configured maximum, which typically signals a misbehaving backend or extremely
large responses.
Parameters:
buffer_size— current size of the buffer in bytesmax— the configured maximum in bytes
Emit a span exception event when a unit of work fails.
The event is published at [:beam_agent, agent, event_suffix, :exception].
Call this instead of span_stop/3 when the work raised an error or exception.
Parameters:
agent— backend atomsuffix— operation atom, must match thespan_start/3callreason— the error reason or exception term
Emit a span exception event with additional metadata.
Same as span_exception/3 but merges caller-supplied metadata into the
emitted exception event.
Emit a span start event and return a monotonic start time.
The returned integer must be passed unchanged to span_stop/3 or
span_exception/3 so the duration can be computed.
Parameters:
agent— backend atom, e.g.:claude,:codex,:geminievent_suffix— atom labelling the operation, e.g.:query,:connectmetadata— arbitrary map attached to the telemetry event
Returns a monotonic integer (result of :erlang.monotonic_time/0).
Example
t = BeamAgent.Telemetry.span_start(:claude, :query, %{session_id: id})
# work...
BeamAgent.Telemetry.span_stop(:claude, :query, t)
Emit a span stop event, computing duration from the start time.
The event is published at [:beam_agent, agent, event_suffix, :stop] with a
duration measurement in native time units.
Parameters:
agent— same atom passed tospan_start/3suffix— same atom passed tospan_start/3start_time— the integer returned byspan_start/3
Emit a span stop event with additional metadata.
Same as span_stop/3 but merges caller-supplied metadata into the stop event.
Emit a state change event for a gen_statem transition.
The event is published at the fixed path [:beam_agent, :session, :state_change].
Backend session handlers call this on every state machine transition so that
consumers can observe the full session lifecycle.
Parameters:
agent— backend atom identifying which session handler firedfrom_state— the state the session is leaving (e.g.:connecting,:ready)to_state— the state the session is entering
Valid state atoms: :connecting, :initializing, :ready, :active_query,
:error.
Emit a state change event for a non-session BeamAgent domain.
The event is published at [:beam_agent, domain, :state_change].
Canonical BeamAgent domains such as runs, steps, and routines use this helper
to report lifecycle transitions without inventing a second telemetry style.