Pure functions for WebSocket session recording and replay.
Records WebSocket frames to JSONL format (one JSON object per line) for debugging, testing, and analysis. Each entry includes timestamp, direction, frame type, and data.
JSONL Format
{"ts":"2026-01-20T15:30:45.123456Z","dir":"out","type":"text","data":"..."}
{"ts":"2026-01-20T15:30:45.234567Z","dir":"in","type":"text","data":"..."}
{"ts":"2026-01-20T15:30:46.000000Z","dir":"in","type":"binary","data":"base64...","binary":true}Usage
# Format an entry for recording
line = Recorder.format_entry(:out, {:text, "hello"}, DateTime.utc_now())
# Parse an entry from a recording
{:ok, entry} = Recorder.parse_entry(line)
# Replay a recording
Recorder.replay("/tmp/session.jsonl", fn entry ->
# Process each entry (e.g., send to handler, accumulate stats)
handle_entry(entry)
end)
# Get metadata about a recording
{:ok, meta} = Recorder.metadata("/tmp/session.jsonl")
# => %{count: 150, duration_ms: 5234, first_ts: ~U[...], last_ts: ~U[...]}API Functions
| Function | Arity | Description | Param Kinds |
|---|---|---|---|
metadata | 1 | Get metadata about a recorded session. | path: value |
replay | 3 | Replay a recorded session, calling handler for each entry. | path: value, handler_fn: value, opts: value |
parse_entry | 1 | Parse a JSONL line back into an entry map. | line: value |
format_entry | 3 | Format a WebSocket frame as a JSONL line for recording. | direction: value, frame: value, timestamp: value |
Summary
Functions
Formats a WebSocket frame as a JSONL line for recording.
Gets metadata about a recorded session.
Parses a JSONL line back into an entry map.
Replays a recorded session by streaming the file and calling the handler for each entry.
Types
Functions
@spec format_entry(direction(), frame(), DateTime.t()) :: binary()
Formats a WebSocket frame as a JSONL line for recording.
Parameters
direction-:infor received frames,:outfor sent framesframe- The WebSocket frame tuple{:text, data},{:binary, data}, or{:close, code, reason}timestamp- The timestamp for this entry (default: current UTC time)
Examples
iex> line = Recorder.format_entry(:out, {:text, "hello"}, ~U[2026-01-20 15:30:45.123456Z])
~s({"ts":"2026-01-20T15:30:45.123456Z","dir":"out","type":"text","data":"hello"})
iex> line = Recorder.format_entry(:in, {:binary, <<1, 2, 3>>}, ~U[2026-01-20 15:30:45Z])
~s({"ts":"2026-01-20T15:30:45.000000Z","dir":"in","type":"binary","data":"AQID","binary":true})
Gets metadata about a recorded session.
Returns information about the recording including entry count, duration, and timestamp range.
Examples
{:ok, meta} = Recorder.metadata("/tmp/session.jsonl")
# => %{
# count: 150,
# duration_ms: 5234,
# first_ts: ~U[2026-01-20 15:30:45.123456Z],
# last_ts: ~U[2026-01-20 15:30:50.357456Z],
# inbound: 100,
# outbound: 50
# }
Parses a JSONL line back into an entry map.
Examples
iex> {:ok, entry} = Recorder.parse_entry(~s({"ts":"2026-01-20T15:30:45.123456Z","dir":"out","type":"text","data":"hello"}))
iex> entry.dir
:out
iex> entry.data
"hello"
Replays a recorded session by streaming the file and calling the handler for each entry.
Options
:realtime- If true, delays between entries match the original timing (default: false)
Examples
# Fast replay
Recorder.replay("/tmp/session.jsonl", fn entry ->
IO.puts("#{entry.dir}: #{entry.type}")
end)
# Realtime replay
Recorder.replay("/tmp/session.jsonl", &IO.inspect/1, realtime: true)