Skip to main content

Module stats

Module stats 

Source
Expand description

Traffic counter collection for moq-net sessions.

This module only collects: build a Registry, hand each session a tier-scoped Handle via Registry::tier, and read the counters back with Registry::snapshot (host-level rollup, e.g. a /metrics scrape) or Registry::report (per-broadcast detail). Publishing the counters as MoQ broadcasts lives in the moq-stats crate, which drains a Registry on an interval and writes the JSON stats tracks.

Traffic is bucketed by an arbitrary Tier label chosen by business logic (billing class, region, …) and, within a tier, by broadcast path and Role (publisher = egress, subscriber = ingress). Connected sessions are tracked separately per (tier, auth root), counting presence regardless of whether any data flows.

§Where counting happens

Counting lives in the model layer, not the wire loops. A session tags its origin pair with a Session context (crate::Client::with_stats / crate::Server::with_stats, which call origin::{Consumer, Producer} with_stats); every derived handle (broadcast, announce, track, group, frame) then attributes its reads (egress = publisher) and writes (ingress = subscriber) through that context. So any protocol that drives the model gets the full counter set for free, and an untagged handle pays nothing.

Per-counter semantics:

  • announced / announced_closed: cumulative broadcast announce/unannounce events on this (tier, role). Driven by the tagged announce stream on the egress side, and by create_broadcast route transitions on the ingress side.
  • announced_bytes: cumulative broadcast-name length summed over each model-visible announce and unannounce of this broadcast (the name, not the encoded message size, so hop/framing overhead isn’t charged, and the count is the same across protocol versions). Kept separate from the bytes payload counter.
  • broadcasts / broadcasts_closed: per-(broadcast, context) egress subscription sentinel. The first active subscription a context opens for a broadcast bumps broadcasts; the last it closes bumps broadcasts_closed. Summed across contexts, broadcasts - broadcasts_closed is the number of distinct sessions currently subscribed (viewers on the egress side).
  • subscriptions / subscriptions_closed: cumulative track-level subscriptions opened/dropped (egress track::Subscriber, ingress track::Producer).
  • fetches: cumulative one-shot group fetches requested by a calling context, counted once per coalesced fetch at request time. A fetch that resolves to NotFound still counts. Separate from subscriptions and the viewer refcount; fetched payload still flows into bytes / frames / groups.
  • bytes / frames / groups: cumulative payload counters bumped as groups/frames are read (egress) or written (ingress) in the model.
  • datagrams: cumulative single-frame groups carried over unreliable QUIC datagrams. A datagram is metered as the group it stands in for, so it also bumps groups, frames, and bytes; this counter breaks out how many of those took the datagram path.
  • sessions / sessions_closed (Presence): cumulative count of sessions connected/disconnected under an auth root on this tier. Driven by Handle::session (the Session context).

Counters are strictly monotonic (only fetch_add); a counter going backwards across reads means the underlying entry was garbage collected (see Registry::report) and re-created. Downstream consumers should treat decreases as a fresh segment, summing across resets when computing lifetime totals.

§Disabled stats

Registry::disabled builds a no-op registry: all counter bumps are silently dropped and nothing is ever tracked. Registry::default / Handle::default return one, so call sites can hold a Handle unconditionally instead of threading an Option.

§Garbage collection

Registry::report returns the current per-broadcast detail and prunes entries no longer referenced by any guard, so a publisher draining the registry on an interval keeps it bounded. A registry that is never drained accumulates one entry per broadcast path ever seen; call Registry::report periodically if you enable a registry without attaching a publisher. Registry::snapshot never prunes.

§Snapshot atomicity

Each counter readout loads *_closed atomics (with Acquire) before their open counterparts (with Relaxed). The matching close bumps in the RAII guards’ Drop impls use Release. With this pairing the readout always satisfies open >= closed even on weakly-ordered architectures (ARM, POWER): the Acquire load of close synchronizes-with the Release bump that produced the observed value, making every write that happened-before that close (including the matching open bump on whichever thread opened the guard) visible to the reading thread. Open / payload counters can then stay Relaxed because the visibility comes for free through the close pairing. The cost is a slight upward bias on the open counts when a bump lands between the two loads, which never produces a logically impossible (closed > open) readout for downstream.

§Cycles

A Registry built with excluded prefixes (Config::exclude) returns empty handles (whose bumps no-op) for any path under one of them. The moq-stats publisher excludes its own top-level prefix this way, breaking the feedback loop where serving a stats broadcast would itself generate more stats traffic.

Structs§

Config
Settings for a Registry. Construct with Config::new and chain the with_* setters, then hand it to Registry::new.
Handle
Tier-scoped wrapper around Registry. What crate::Client::with_stats and crate::Server::with_stats accept. Cheap to clone.
Presence
Connected-session presence for one slice (an auth root on a tier, or any sum of such slices): cumulative connects and disconnects. sessions - sessions_closed is the current live session count.
Registry
Counter collection registry. Cheap to clone (Arc inside for the shared state). One instance per relay; sessions get tier-scoped handles via Registry::tier. The moq-stats crate drains it with Registry::report to publish the counters as MoQ broadcasts.
Report
The per-broadcast detail returned by Registry::report: one traffic entry per (broadcast, tier) and one session entry per (tier, root). Entries are unordered.
Session
Per-connection stats context, created via Handle::session.
SessionEntry
One (tier, root) row of a Report.
Snapshot
A point-in-time, host-level rollup of a registry’s counters, returned by Registry::snapshot.
Tier
Traffic-class label that selects which counter set a session’s bumps record in, so a single Registry can split customer-facing, cluster-peer, regional, etc. traffic. Each tracked broadcast keeps a per-tier counter set on both its publisher and subscriber sides.
Traffic
A cumulative traffic counter readout for one slice (a broadcast on a (tier, role), or any sum of such slices).
TrafficEntry
One (broadcast, tier) row of a Report.

Enums§

Role
Publisher (egress) vs subscriber (ingress) side of a broadcast, used as a label on a Snapshot traffic row. The internal bump paths track the side statically, so this only surfaces on the aggregate read side.