Seeing What Happened
View SourceAfter: You can see what your agent did via logs and telemetry.
When your agent runs, Jido emits telemetry events and structured logs automatically. This guide shows you how to observe agent behavior during development.
Quick Start: Enable Debug Logging
Add this to config/dev.exs:
config :logger, level: :debugNow when you run cmd/2 or start an AgentServer, you'll see structured log output.
Instance-Scoped Debug (Recommended for Development)
The fastest way to see what's happening during development is instance-level debug mode:
MyApp.Jido.debug(:on) # developer-friendly verbosity for this instance
MyApp.Jido.debug(:verbose) # maximum detail — trace-level, full args
MyApp.Jido.debug(:off) # back to configured defaultsThis enables debug logging and event recording for all agents in the instance without changing the global logger level. You still need config :logger, level: :debug in your config/dev.exs so the Logger doesn't filter out debug messages before Jido sees them.
What Gets Logged
When you execute a command:
{agent, directives} = MyAgent.cmd(agent, {SomeAction, %{value: 42}})You'll see output like:
[debug] [Agent] Command started agent_id="agent_abc123" agent_module=MyAgent action="{SomeAction, %{value: 42}}"
[debug] [Agent] Command completed agent_id="agent_abc123" duration_μs=1234 directive_count=2AgentServer operations log signal processing:
[debug] [AgentServer] Signal processing started agent_id="agent_abc123" signal_type="jido.agent.cmd"
[debug] [AgentServer] Signal processing completed agent_id="agent_abc123" duration_μs=5678 directive_count=1Telemetry Events
Jido emits these events automatically:
| Event | When |
|---|---|
[:jido, :agent, :cmd, :start] | cmd/2 begins |
[:jido, :agent, :cmd, :stop] | cmd/2 completes |
[:jido, :agent, :cmd, :exception] | cmd/2 raises |
[:jido, :agent_server, :signal, :start] | Signal processing begins |
[:jido, :agent_server, :signal, :stop] | Signal processing completes |
[:jido, :agent_server, :directive, :start] | Directive execution begins |
[:jido, :agent_server, :directive, :stop] | Directive execution completes |
[:jido, :agent, :strategy, :cmd, :start] | Strategy executes command |
[:jido, :agent, :strategy, :cmd, :stop] | Strategy command completes |
All events include metadata:
:agent_id— the agent's unique identifier:agent_module— the agent module name:jido_instance— the Jido instance that owns this agent (ornilin non-instance contexts):duration— execution time (nanoseconds, on:stopevents):directive_count— number of directives produced
Attach a Handler
Attach your own telemetry handler to collect metrics or log in your preferred format:
defmodule MyApp.JidoMetrics do
require Logger
def setup do
:telemetry.attach_many(
"my-jido-handler",
[
[:jido, :agent, :cmd, :stop],
[:jido, :agent, :cmd, :exception],
[:jido, :agent_server, :signal, :stop]
],
&__MODULE__.handle_event/4,
nil
)
end
def handle_event([:jido, :agent, :cmd, :stop], measurements, metadata, _config) do
duration_ms = System.convert_time_unit(measurements.duration, :native, :millisecond)
Logger.info("Agent command completed",
agent_id: metadata.agent_id,
jido_instance: metadata.jido_instance,
duration_ms: duration_ms,
directives: metadata.directive_count
)
end
def handle_event([:jido, :agent, :cmd, :exception], _measurements, metadata, _config) do
Logger.error("Agent command failed",
agent_id: metadata.agent_id,
error: inspect(metadata.error)
)
end
def handle_event([:jido, :agent_server, :signal, :stop], measurements, metadata, _config) do
duration_ms = System.convert_time_unit(measurements.duration, :native, :millisecond)
Logger.info("Signal processed",
agent_id: metadata.agent_id,
signal_type: metadata.signal_type,
duration_ms: duration_ms
)
end
endCall MyApp.JidoMetrics.setup() in your application startup.
Correlation IDs
Jido automatically correlates signals across a processing chain. When trace context is active, telemetry metadata includes:
:jido_trace_id— shared across the entire call chain:jido_span_id— unique to the current operation:jido_parent_span_id— the parent operation that triggered this one:jido_causation_id— the signal ID that caused this signal
Use these to trace a request through multiple agents or action chains:
def handle_event(event, measurements, metadata, _config) do
if trace_id = metadata[:jido_trace_id] do
Logger.metadata(trace_id: trace_id)
end
# Your logging/metrics code
endLocal Introspection (Debug Mode)
For quick debugging without setting up telemetry handlers, debug mode records recent events in an in-memory ring buffer (500 events by default, configurable via debug_max_events).
Instance-Level Debug (Primary Workflow)
Enable debug for an entire instance — all agents in that instance start recording events immediately:
MyApp.Jido.debug(:on)
# ... run some operations ...
{:ok, events} = MyApp.Jido.recent(pid, 10)Check the current debug state with:
MyApp.Jido.debug_status()Per-Agent Debug
For surgical debugging of a single agent, per-agent opt-in still works:
{:ok, pid} = MyApp.Jido.start_agent(MyAgent, debug: true)Boot-Time Config
Enable debug at startup via application config:
# config/dev.exs
config :my_app, MyApp.Jido, debug: trueSee Runtime - Debug Mode for details.
Next Steps
This guide covers development observability. For a step-by-step debugging workflow, see Debugging. For production monitoring with custom metrics, OpenTelemetry integration, and performance dashboards, see Observability.
Key modules:
Jido.Telemetry— built-in telemetry handler and event definitionsJido.Observe— unified observability façade with span helpersJido.Observe.Config— per-instance observability config resolutionJido.Debug— per-instance runtime debug modeJido.Tracing.Context— correlation ID propagation