Skip to content

feat(statistic): add opt-in per-host traffic statistics - #3389

Open
hakku615 wants to merge 1 commit into
MetaCubeX:Alphafrom
hakku615:feat/traffic-stats
Open

hakku615 wants to merge 1 commit into
MetaCubeX:Alphafrom
hakku615:feat/traffic-stats

Conversation

@hakku615

@hakku615 hakku615 commented Nov 1, 2026

Copy link
Copy Markdown

Motivation

The controller exposes traffic per connection, but nothing aggregates it by destination host over time. Closed connections disappear from snapshots, so external pollers both miss short connections and lose the tail of longer ones.

Related: #2478 (persistent per-client statistics), #3127 (report short-lived connections in snapshots).

Change

  • Record traffic per destination host (falling back to the destination IP), split between proxied and direct connections.
  • Sample active trackers every second and settle the remaining bytes in Manager.Leave, so short connections and their tails are accounted for exactly.
  • Keep minute buckets for 24h and daily buckets for a configurable retention (30 days by default), pruned on a timer.
  • Bound memory by evicting the least recently updated hosts when traffic-stats-max-hosts is reached.
  • Persist to traffic-stats.json periodically and on shutdown, restoring on startup.
  • New endpoints:
    • GET /traffic/hosts?since=&until=&domain=&match=suffix|exact&group=proxy|direct|all&top=
    • GET /traffic/hosts/check — session totals versus kernel counters, for reconciliation

Configuration

profile:
  store-traffic-stats: true            # default false
  traffic-stats-retention-days: 30
  traffic-stats-max-hosts: 20000
  traffic-stats-persist-interval: 300

The feature is disabled by default, so existing deployments are unaffected. Both endpoints return 404 while it is disabled, and the existing /connections response is unchanged.

Testing

  • go test ./tunnel/statistic/ covers first-sample accounting, delta sampling, close settlement, the proxy/direct split, suffix versus exact matching, time-range filtering, IP fallback, eviction, persistence round-trip and the disabled state.
  • Verified on a live instance: /traffic/hosts/check reports a stable zero delta between the aggregated statistics and the kernel counters, including across a 1.5 MB transfer.

Record traffic grouped by destination host (falling back to the destination
IP), split between proxied and direct connections, and expose it through two
new controller endpoints.

- sample active trackers every second and settle the remaining bytes in
  Manager.Leave so that short connections and their tails are not lost
- keep minute buckets for 24h and daily buckets for the configured retention
  (30 days by default)
- bound memory with an LRU-ish eviction when the host limit is reached
- persist to traffic-stats.json periodically and on shutdown
- GET /traffic/hosts: aggregate a time range, filter by domain
  (suffix/exact) and by proxy/direct, sort by total, limit with top
- GET /traffic/hosts/check: compare session totals against the kernel
  counters for reconciliation

The feature is disabled by default and enabled with
profile.store-traffic-stats, so existing deployments are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant