Jido. Signal. TraceContext
(Jido Signal v2.2.2)
View Source
Process-dictionary-based trace context management.
Stores current trace context in the process dictionary so it can be accessed when creating new signals without explicit parameter passing.
Usage Pattern
- Ingress: When receiving a signal, set context from the signal
- Processing: Access context when creating outbound signals
- Egress: Clear context when done
Examples
# At ingress point (e.g., AgentServer.handle_call)
{signal, ctx} = TraceContext.ensure_from_signal(signal)
# During processing - context available automatically
ctx = TraceContext.current()
# When emitting signals, propagate trace as child
{:ok, traced_signal} = TraceContext.propagate_to(outbound_signal, input_signal.id)
# At egress
TraceContext.clear()Thread Safety
Process dictionary is per-process, so context is automatically isolated. For Task.async or spawn, context must be explicitly passed and restored.
Example: Spawning with Context
# Capture context before spawning
ctx = TraceContext.current()
Task.async(fn ->
# Restore context in spawned process
TraceContext.set(ctx)
# Now context is available in the spawned task
TraceContext.current()
end)See Also
Jido.Signal.Trace- Low-level trace context creation and manipulationJido.Signal.Trace.Context- The trace context structJido.Signal.Ext.Trace- The trace extension for signals
Summary
Functions
Builds child context from current process context.
Clears the trace context from the process dictionary.
Gets the current trace context from the process dictionary.
Ensures trace context is set from a signal.
Ensures trace context is set from a state map containing a current_signal.
Adds current trace context as child to an outbound signal.
Sets the trace context in the process dictionary.
Sets trace context from a signal's extension data.
Converts current trace context to metadata map for telemetry/observability.
Converts a trace context to metadata map for telemetry/observability.
Wraps a function with trace context preservation.
Functions
@spec child_context(String.t() | nil) :: Jido.Signal.Trace.Context.t()
Builds child context from current process context.
If there's a current trace context, creates a child span linked to it. If no current context, creates a new root trace.
Examples
# With existing context - creates child
TraceContext.set(parent_ctx)
child = TraceContext.child_context("input-signal-id")
child.trace_id #=> parent_ctx.trace_id (inherited)
child.parent_span_id #=> parent_ctx.span_id (linked)
# Without context - creates root
TraceContext.clear()
root = TraceContext.child_context("input-signal-id")
root.parent_span_id #=> nil
@spec clear() :: :ok
Clears the trace context from the process dictionary.
Returns :ok.
Examples
iex> TraceContext.set(ctx)
iex> TraceContext.clear()
:ok
iex> TraceContext.current()
nil
@spec current() :: Jido.Signal.Trace.Context.t() | nil
Gets the current trace context from the process dictionary.
Returns nil if no context is set.
Examples
iex> TraceContext.current()
nil
iex> TraceContext.set(ctx)
iex> TraceContext.current()
%Context{trace_id: "abc123", span_id: "def456"}
@spec ensure_from_signal( Jido.Signal.t(), keyword() ) :: {Jido.Signal.t(), Jido.Signal.Trace.Context.t()}
Ensures trace context is set from a signal.
If the signal has trace context, extracts and sets it. If not, creates a new root trace, adds it to the signal, and sets it.
Returns {signal, trace_context} where signal may be updated with trace.
Options
:causation_id- Optional causation reference for new root traces:tracestate- Optional W3C tracestate for new root traces
Examples
# Signal without trace - creates new root
{traced_signal, ctx} = TraceContext.ensure_from_signal(signal)
# Signal with trace - uses existing
{signal, ctx} = TraceContext.ensure_from_signal(traced_signal)
@spec ensure_set_from_state(map()) :: :ok | :error
Ensures trace context is set from a state map containing a current_signal.
This is a convenience for extracting trace from agent state patterns that store the current signal being processed.
Returns :ok if context was set, :error if no signal or no trace.
Examples
state = %{current_signal: traced_signal, other: :data}
:ok = TraceContext.ensure_set_from_state(state)
@spec propagate_to(Jido.Signal.t(), String.t() | nil) :: {:ok, Jido.Signal.t()} | {:error, term()}
Adds current trace context as child to an outbound signal.
Creates a child span linked to the current process context and adds it to the signal.
Examples
# Set up parent context
TraceContext.set(parent_ctx)
# Create outbound signal
{:ok, signal} = Signal.new("user.created", %{user_id: "123"})
# Propagate trace as child
{:ok, traced} = TraceContext.propagate_to(signal, "input-signal-id")
Trace.get(traced).trace_id #=> parent_ctx.trace_id (inherited)
Trace.get(traced).parent_span_id #=> parent_ctx.span_id (linked)
Trace.get(traced).causation_id #=> "input-signal-id"
@spec set(Jido.Signal.Trace.Context.t()) :: :ok
Sets the trace context in the process dictionary.
Returns :ok.
Examples
iex> TraceContext.set(ctx)
:ok
@spec set_from_signal(Jido.Signal.t()) :: :ok | :error
Sets trace context from a signal's extension data.
Extracts trace context from the signal's correlation extension
and sets it in the process dictionary.
Returns :ok if context was set, :error if signal has no trace.
Examples
:ok = TraceContext.set_from_signal(traced_signal)
@spec to_telemetry_metadata() :: map()
Converts current trace context to metadata map for telemetry/observability.
Returns a flat map with jido_ prefixed keys suitable for telemetry metadata.
Examples
TraceContext.set(ctx)
TraceContext.to_telemetry_metadata()
#=> %{
#=> jido_trace_id: "abc",
#=> jido_span_id: "def",
#=> jido_parent_span_id: "parent",
#=> jido_causation_id: nil
#=> }
@spec to_telemetry_metadata(Jido.Signal.Trace.Context.t() | nil) :: map()
Converts a trace context to metadata map for telemetry/observability.
Examples
TraceContext.to_telemetry_metadata(ctx)
#=> %{jido_trace_id: "abc", jido_span_id: "def", ...}
TraceContext.to_telemetry_metadata(nil)
#=> %{jido_trace_id: nil, jido_span_id: nil, ...}
@spec with_context(Jido.Signal.t() | Jido.Signal.Trace.Context.t(), (-> result)) :: result when result: term()
Wraps a function with trace context preservation.
Sets context from the signal or context before executing the function, and clears it after (even if the function raises).
Examples
# With a signal
result = TraceContext.with_context(traced_signal, fn ->
# Context is available here
ctx = TraceContext.current()
# ... do work ...
:result
end)
# Context is cleared after
# With explicit context
result = TraceContext.with_context(ctx, fn ->
TraceContext.current() #=> ctx
:result
end)