Skip to content

Initial Filter Support framework, notificaitons and track filters - #1

Open
suhasHere wants to merge 88 commits into
upstream-publish-subscribefrom
pending-filter
Open

Initial Filter Support framework, notificaitons and track filters #1
suhasHere wants to merge 88 commits into
upstream-publish-subscribefrom
pending-filter

Conversation

@suhasHere

Copy link
Copy Markdown
Owner

This build on SubNs support PR cloudflare#157 and adds sub-ns state management, object filter inspection framework and then adds top-n track fitler support on top of it. The base framework can be reused for other object filtering logic

itzmanish and others added 30 commits December 19, 2025 00:12
…for up to 1 second for SubscribeOk to arrive

-remove panic if Fetch stream header
…acade

Adds optional metrics support behind the 'metrics' feature flag. When
disabled, all instrumentation compiles to zero-cost no-ops.

## Metrics (15 total)

### Counters (7)
- moq_relay_connections_total: Total incoming connections
- moq_relay_connection_errors_total{stage}: Connection failures
- moq_relay_publishers_total: Total ANNOUNCE requests
- moq_relay_announce_errors_total: Announce handling failures
- moq_relay_subscribers_total: Total SUBSCRIBE requests
- moq_relay_subscribe_failures_total{reason}: Subscription failures
- moq_relay_upstream_errors_total{stage}: Upstream connection failures

### Gauges (6)
- moq_relay_active_connections: Current client connections
- moq_relay_active_publishers: Current publishers
- moq_relay_active_subscriptions: Current subscriptions
- moq_relay_active_tracks: Tracks being served
- moq_relay_announced_namespaces: Registered namespaces
- moq_relay_upstream_connections: Upstream/origin connections

### Histograms (2)
- moq_relay_connection_duration_seconds: Connection lifetimes
- moq_relay_subscribe_latency_seconds{source}: Subscription resolution time

## Implementation

- GaugeGuard: RAII guard for gauge increment/decrement
- TimingGuard: RAII guard for histogram duration recording
- Both guards have #[must_use] to prevent accidental drops
- All metrics prefixed with moq_relay_ for namespace safety

Consumers install their own metrics::Recorder to route these
to their preferred backend (Prometheus, StatsD, etc.).
…lidation

Add --metrics-addr CLI flag and metrics-prometheus feature to enable
direct Prometheus metrics exposure from the standalone relay binary.
This allows testing and validation of metrics without the crique
adapter layer.

Changes:
- Add metrics-exporter-prometheus optional dependency
- Add metrics-prometheus feature (implies metrics feature)
- Add --metrics-addr <addr> CLI flag to expose /metrics endpoint
- Remove connection_duration_seconds histogram (not suitable for
  long-lived connections; use active_connections gauge instead)
- Configure histogram buckets for subscribe_latency_seconds (1ms-10s)

Usage:
  cargo build -p moq-relay-ietf --features metrics-prometheus
  ./moq-relay-ietf --metrics-addr 127.0.0.1:9090 ...
  curl http://127.0.0.1:9090/metrics
Add SessionError::is_graceful_close() method to detect when a connection
ended due to a graceful APPLICATION_CLOSE (code 0) vs an actual error.

Changes:
- moq-transport: Add is_graceful_close() helper that checks error strings
  for graceful close patterns (transport-agnostic for future tokio-quiche)
- moq-relay-ietf: Add connections_closed_total counter (always increments)
- moq-relay-ietf: Only increment connection_errors_total for actual errors

This allows dashboards/alerts to distinguish between healthy disconnects
and error conditions. Previously all session closes were counted as errors.
- Fix is_graceful_close() for WebTransport connections
  - Add web-transport-quinn, web-transport-proto, and quinn dependencies
  - Use structural pattern matching instead of string matching
  - Properly decode HTTP/3 encoded WebTransport close codes
  - Add detailed comments about coupling to quinn backend

- Fix subscribe failure double-counting
  - Split subscribe_failures_total into separate counters:
    - subscribe_not_found_total: track not found after checking all sources
    - subscribe_route_errors_total: infrastructure failure when routing
  - Route errors now return early with internal error instead of falling
    through to also count as not_found
  - Add route_error as a possible source label for subscribe latency

- Fix connections_closed_total accounting gap
  - Increment connections_closed_total when session_accept fails
  - Maintains invariant: connections_total - connections_closed_total == active_connections
The metrics crate facade is effectively zero-cost when no recorder is
installed (an atomic load + early return), similar to the log crate.
Remove the 'metrics' feature flag and all 21 #[cfg(feature = "metrics")]
annotations.

The metrics-prometheus feature remains for the optional Prometheus
exporter, which brings heavier dependencies.

This simplifies every call site from:
  #[cfg(feature = "metrics")]
  metrics::counter!("...").increment(1);
to just:
  metrics::counter!("...").increment(1);

Also removes the ZST stub implementations of GaugeGuard and TimingGuard
that were needed for the feature-disabled code path.
The upstream_connections gauge was incrementing before the QUIC
connection and MoQ session were established. If either step failed,
the gauge briefly spiked and then decremented — misrepresenting
the number of active upstream connections.

Move the GaugeGuard creation to after both connect() and
Subscriber::connect() succeed so the gauge only reflects
established upstream connections. Failed attempts are already
captured by the upstream_errors_total counter.
Register metric descriptions with the recorder so they appear as
# HELP comments in Prometheus output. Called after installing the
exporter in main.rs.
- Format main.rs and relay.rs
- Replace try_from().unwrap() with infallible from() in varint tests
Replace the log crate with tracing throughout the codebase as Phase 1
of the logging/tracing migration. This aligns moq-rs with the broader
Rust ecosystem (tokio, hyper, axum) and enables future enhancements
like structured fields and spans.

Changes:
- Replace all log::{trace,debug,info,warn,error}! macros with tracing equivalents
- Update Cargo.toml files to use tracing and tracing-subscriber
- Remove log and env_logger dependencies from workspace
- Update binary main.rs files to use tracing_subscriber::fmt() with EnvFilter
- Default log filter: info level with quinn=warn to suppress QUIC noise

Backward compatible:
- RUST_LOG environment variable still works
- Output destination unchanged (stdout/stderr)
- Log message format unchanged for this phase
Add structured tracing fields (namespace, track, error, source, etc.)
to log messages in moq-relay-ietf while preserving the original message
format for backward compatibility with existing text-based searches.

This enables:
- Filtering logs by namespace/track in Elasticsearch
- Structured queries without breaking existing workflows
- Easier debugging by having key identifiers as separate JSON fields

Files updated:
- consumer.rs: announce/subscribe flows
- producer.rs: subscribe/track_status handling
- relay.rs: session error handling
- remote.rs: remote origin handling
- file_coordinator.rs: namespace registration
- api_coordinator.rs: API-based coordination

The message body remains unchanged - fields are duplicated in both
the message string and as separate structured fields.
Add debug-level tracing logs for all MoQT control messages sent and
received on the control stream. Each log includes:
- direction: 'sent' or 'recv'
- msg_type: message type name (e.g., SUBSCRIBE, PUBLISH_NAMESPACE_OK)
- Message-specific fields matching the mlog schema

Uses custom target 'moq_transport::control' so these logs can be
filtered independently via tracing-subscriber's EnvFilter. This
allows applications like crique to enable these logs in production
while keeping moq-transport quiet by default for other users.

Control messages logged:
- Setup: CLIENT_SETUP, SERVER_SETUP
- Subscribe family: SUBSCRIBE, SUBSCRIBE_OK, SUBSCRIBE_ERROR,
  SUBSCRIBE_UPDATE, UNSUBSCRIBE
- PublishNamespace family: PUBLISH_NAMESPACE, PUBLISH_NAMESPACE_OK,
  PUBLISH_NAMESPACE_ERROR, PUBLISH_NAMESPACE_DONE,
  PUBLISH_NAMESPACE_CANCEL
- TrackStatus family: TRACK_STATUS, TRACK_STATUS_OK, TRACK_STATUS_ERROR
- SubscribeNamespace family: SUBSCRIBE_NAMESPACE,
  SUBSCRIBE_NAMESPACE_OK, SUBSCRIBE_NAMESPACE_ERROR,
  UNSUBSCRIBE_NAMESPACE
- Fetch family: FETCH, FETCH_OK, FETCH_ERROR, FETCH_CANCEL
- Publish family: PUBLISH, PUBLISH_OK, PUBLISH_ERROR, PUBLISH_DONE
- Session: GOAWAY, MAX_REQUEST_ID, REQUESTS_BLOCKED
Add logging for:
- Announce lifecycle (coordinator registration, locals registration, ANNOUNCE_OK)
- Announce closed events
- Locals deregistration on drop
- Track cache operations (hit/miss/stale eviction)
- Track close and state drop events

Track cache logging uses target 'moq_transport::tracks' for independent filtering.
Upgrade from web-transport v0.3.0 / web-transport-quinn v0.3.4 /
web-transport-proto v0.2.8 to web-transport v0.10.1 /
web-transport-quinn v0.11.4 / web-transport-proto v0.5.2.

The v0.11.x quinn backend has proper support for:

- H3 SETTINGS: ENABLE_DATAGRAM, WEBTRANSPORT_MAX_SESSIONS,
  ENABLE_CONNECT_PROTOCOL, and Chrome-compat deprecated settings
- Capsule protocol for graceful session close
- Sub-protocol negotiation via wt-available-protocols headers
- GREASE filtering in H3 settings
- Session::raw() for clean raw-QUIC (moqt:// scheme) fallback
- Session stores ConnectRequest with URL (enables future path extraction)
- web_transport_trait::Session trait for backend abstraction

API changes adapted:
- ALPN constant changed from &[u8] to &str (.as_bytes() added)
- accept(conn) -> Request::accept(conn) then .ok().await
- connect_with(conn, url) -> Session::connect(conn, url)
- conn.into() -> Session::raw(conn, url, ConnectResponse::default())
- Three error variants collapsed into one web_transport::Error
- is_graceful_close() updated for new error type hierarchy
- Session methods now take &self instead of &mut self
- read_buf() returns Option<usize> instead of bool
- read_chunk() renamed to read()
web-transport-quinn v0.11+ decodes HTTP/3-encoded close codes at the
SessionError level. A WebTransport graceful close (code 0) now arrives as
WebTransportError::Closed(0, "") rather than
ConnectionError::ApplicationClosed(h3_encoded_code).

Without this fix, is_session_error_graceful() returned false for all
WebTransportError variants, misclassifying graceful WebTransport closes
as errors in metrics.
WebTransport graceful close is driven by CLOSE_WEBTRANSPORT_SESSION
capsule (code 0), not APPLICATION_CLOSE directly. Updated doc comments
to distinguish the two transport mechanisms accurately.
web-transport-quinn, web-transport-proto, and quinn are all accessible
via re-exports from the web-transport crate (web_transport::quinn::*,
web_transport::quinn::proto::*, web_transport::quinn::quinn::*).

Removes the direct dependencies, fixing the cargo-machete lint.
The SessionError conversion from ConnectionError via error_from_http3
is the typical path but not guaranteed for all cases. Wording now
reflects that decoding depends on the conversion path being used and
succeeding.
@suhasHere
suhasHere force-pushed the pending-filter branch 4 times, most recently from c56198b to 68f4e43 Compare June 3, 2026 06:14
@suhasHere
suhasHere force-pushed the pending-filter branch 2 times, most recently from b44330a to 93532ac Compare June 3, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

5 participants