Builds v2 flat event envelopes for trace logging.
Transforms raw telemetry data into a flat, queryable JSON structure where
commonly-filtered fields (agent_name, turn, tool_name, tokens, duration)
are promoted to top level. Bulky payloads go into a data bag.
V2 Event Shape
Every event has these top-level fields:
schema_version, event, trace_id, timestamp, seq,
span_id, parent_span_id,
agent_name, agent_id, turn,
duration_ms, input_tokens, output_tokens, total_tokens,
cache_creation_tokens, cache_read_tokens,
tool_name, model, status,
dataConfiguration
Sanitization limits are runtime-configurable via application config:
:trace_max_string_size- Maximum string size in bytes before truncation (default:65_536):trace_max_list_size- Maximum list length before summarizing (default:100):trace_max_map_size- Maximum map size (keys) before summarizing (default:100):trace_preserve_full_keys- Map keys whose string values are never truncated (default:["system_prompt"])
Summary
Functions
Encodes an event map to a JSON string.
Encodes an event map to a JSON string, raising on failure.
Creates a v2 flat event map from telemetry data.
Sanitizes a value for safe JSON encoding.
Returns the current schema version.
Functions
Encodes an event map to a JSON string.
Returns {:ok, json} on success, {:error, reason} on failure.
Encodes an event map to a JSON string, raising on failure.
Creates a v2 flat event map from telemetry data.
Promotes commonly-queried fields to top level and puts remaining
metadata into a data bag. The agent_name field is extracted from
either metadata.agent_name or metadata.agent.name (fallback).
Examples
iex> event = [:ptc_runner, :sub_agent, :run, :start]
iex> measurements = %{system_time: 1000}
iex> metadata = %{agent_name: "test", agent_id: "abc123"}
iex> result = PtcRunner.TraceLog.Event.from_telemetry(event, measurements, metadata, "trace-123")
iex> result["event"]
"run.start"
iex> result["schema_version"]
2
iex> result["agent_name"]
"test"
Sanitizes a value for safe JSON encoding.
Handles:
- PIDs, refs, ports, functions →
inspect/1string - Non-printable binaries →
%{"__binary__" => true, "size" => N} - Large strings (>64KB by default, configurable) → truncated with preview
- Large lists (>100 by default, configurable) →
"List(N items)" - Maps → recursively sanitized
- Structs → converted to maps and sanitized
- Tuples → converted to lists and sanitized
Examples
iex> result = PtcRunner.TraceLog.Event.sanitize(self())
iex> String.starts_with?(result, "#PID<")
true
iex> PtcRunner.TraceLog.Event.sanitize(%{a: 1, b: 2})
%{"a" => 1, "b" => 2}
iex> PtcRunner.TraceLog.Event.sanitize({:ok, "result"})
[:ok, "result"]
iex> PtcRunner.TraceLog.Event.sanitize(<<0, 1, 2, 3>>)
%{"__binary__" => true, "size" => 4}
@spec schema_version() :: pos_integer()
Returns the current schema version.
Examples
iex> PtcRunner.TraceLog.Event.schema_version()
2