moq-stats 0.1.2

Publish and consume MoQ traffic stats: drains a moq-net counter registry into JSON tracks, plain and compressed.
Documentation

Publish and consume MoQ traffic stats.

moq-net collects per-session traffic counters in a stats::Registry; this crate turns that registry into MoQ broadcasts and back:

  • [Producer] drains a registry on an interval and publishes the counters as JSON tracks on an origin.
  • [Consumer] subscribes to one published stats broadcast and yields typed frames, for aggregators, dashboards, and billing meters.
  • [aggregate::Consumer] folds a whole group's per-node broadcasts into one merged view, so a downstream sees a project's total live traffic as if it came from a single node.

Wire format

A [Producer] publishes one broadcast per node at <prefix>/node/<node> (default prefix .stats; the node suffix disambiguates relays sharing a cluster origin and may be multi-segment, e.g. sjc/1). A grouping depth splits that into one broadcast per leading broadcast-path segments at <prefix>/<group>/node/<node>, so a consumer can announce-scope to a single group. Parse announce paths back with [parse_node_path].

Traffic is bucketed by [Tier] (an arbitrary label chosen by business logic: billing class, region, ...). The default tier is unprefixed; a named tier prefixes its track names with its label. Each broadcast carries, per tier, a publisher (egress) and a subscriber (ingress) traffic track plus a sessions track, each in a plain and a compressed flavor:

  • publisher.json / subscriber.json: each frame is a JSON object mapping broadcast path to a cumulative [Traffic] snapshot ([TrafficFrame]), one full snapshot per frame.
  • sessions.json: each frame maps auth root to a cumulative [Presence] gauge ([SessionsFrame]), counting connected sessions regardless of data flow.
  • <name>.json.z: a compressed sibling of each of the above, encoded with [moq_json::snapshot] (group-scoped DEFLATE plus RFC 7396 merge-patch deltas). Since successive stats frames are nearly identical, this is a fraction of the plain track's bytes; read it with [Consumer] (or moq_json directly), not as raw JSON frames.

Named-tier tracks (<tier>/publisher.json, ...) are created the first time traffic records under that label; default-tier tracks always exist and hold {} while idle. Compute names with [traffic_track] / [sessions_track].

An entry appears in a frame while it is live (an open counter still exceeds its *_closed counterpart, so traffic could resume at any moment) or on the tick its snapshot changed, then is dropped once fully closed. Counters are cumulative and monotonic: a downstream aggregator computes rates from successive snapshots, and a counter going backwards means the relay restarted or the entry was garbage collected and re-created, so consumers should treat a decrease as a fresh segment.