Skip to content

galpt/cake-stats

Repository files navigation

cake-stats

Real-time web UI for monitoring CAKE SQM statistics on Linux and OpenWrt routers.

Built for embedded hardware where every allocation matters: Fiber v3 keeps HTTP overhead minimal, zerolog emits structured logs with near-zero allocations, and a dedicated pkg/util package centralises all allocation-heavy string operations so they can be audited and swapped in one place. The result is a single static binary that streams live per-tier CAKE stats to any browser with negligible CPU and memory cost.


Table of Contents

How it looks like

Desktop

Web UI preview
UI for desktop screens

Web UI preview
Graphs for desktop screens

Mobile

Web UI preview
UI for mobile screens

Web UI preview
Graphs for mobile screens

↑ Back to Table of Contents

Status

  • Stable — all parser unit tests passing, binary builds clean for 14 target platforms. See Releases for the current version.

↑ Back to Table of Contents

Features

  • Automatically discovers all CAKE qdiscs via tc -s qdisc, including cake_mq (multi-queue CAKE introduced in Linux 7.0 and backported to OpenWrt): sub-queue statistics are aggregated into a single logical interface entry so TX throughput, latency and drop graphs work correctly on multi-queue NICs
  • Parses every CAKE field: thresh, target, interval, pk_delay, av_delay, sp_delay, backlog, pkts, bytes, way_inds, way_miss, way_cols, drops, marks, ack_drop, sp_flows, bk_flows, un_flows, max_len, quantum
  • Correctly handles diffserv modes: diffserv3, diffserv4, diffserv8, besteffort, precedence; also parses the separate fwmark MASK tin-override parameter
  • Two-word tier names are joined correctly (e.g. "Best Effort")
  • Real-time push via Server-Sent Events — no WebSocket, no polling jitter
  • Built on Fiber v3 with zerolog for structured logs
  • Default poll interval 100ms for near-instant UI updates (adjustable via -interval)
  • Single static binary — no runtime dependencies
  • Web UI: dark TUI aesthetic (#2D3C59 bg, JetBrains Mono, zero hover animations)
  • Responsive for desktop and mobile (sticky first column, horizontal scroll on small screens)
  • Per-interface live sparklines (TX throughput, avg latency, drops/s) with current-value labels
  • Tap/click any sparkline bar to open a full-screen history modal with three uPlot time-series charts
  • Server-side ring buffer retains history across page reloads (configurable via -history flag)

↑ Back to Table of Contents

Requirements

  • Linux kernel with tc + sch_cake module loaded, or OpenWrt with kmod-sched-cake
  • Go 1.25+ (build only; not needed at runtime)
  • Third-party libraries used during build/services:
    • Fiber v3 – HTTP framework
    • zerolog – structured logging
    • easyjson – JSON code generation; pkg/types/types_easyjson.go is checked in and generated via //go:generate easyjson -all in pkg/types/types.go. CI installs the easyjson binary and re-runs go generate ./... on every build to keep the generated file in sync.
    • rtnetlink – optional netlink client (not currently used; included in go.mod for future event‑based polling)

↑ Back to Table of Contents

Design Notes

  • Modular architecture: code is split into pkg/parser, pkg/history, pkg/server, pkg/log, pkg/types, and pkg/util, with the CLI entrypoint under cmd/cake-stats. pkg/util centralises all allocation-heavy string/byte helpers (split, trim, parse, zero-copy byte↔string conversions) so every other package imports one place instead of duplicating strconv/strings call sites. This keeps the core logic reusable and simplifies testing.
  • Zero-allocation philosophy: hot paths avoid heap allocations by using sync.Pool for temporary buffers, easyjson-generated marshalers (MarshalEasyJSON/UnmarshalEasyJSON in pkg/types/types_easyjson.go) that skip reflection entirely, zero-copy unsafe-backed byte↔string conversions in pkg/util, and pre‑computed byte slices. The 100 ms poll loop is designed to run with minimal GC pressure.
  • Ring buffer history: a thread-safe circular buffer stores past snapshots; clients receive both current data and historical samples after reconnects or page loads.
  • Polling strategy: defaults to 100 ms for near-instant updates; interval is command-line configurable. The codebase contains scaffolding and a placeholder comment for an optional rtnetlink-based watcher, but the current release still relies on regular tc invocations.
  • Server-Sent Events: statistics are broadcast over SSE. A pool of reusable message buffers reduces allocations when many clients connect.
  • Fiber & zerolog: Fiber v3 provides a lightweight HTTP server with built‑in recovery middleware; zerolog supplies compact, structured log output.
  • Single static binary: the project builds to one statically-linked executable, suitable for OpenWrt.
  • Testing and documentation: pkg/parser, pkg/history, and pkg/util include unit tests; pkg/history also includes a benchmark (BenchmarkHistoryRecord). Dependencies are kept to a minimum to ease audits.

↑ Back to Table of Contents

Build

git clone https://github.com/galpt/cake-stats
cd cake-stats
go test ./...          # prints ok for each package with tests
go build -ldflags "-s -w -X main.Version=1.0.0" -o cake-stats ./cmd/cake-stats

Note

pkg/types/types_easyjson.go is checked in, so a normal go build works without extra tools. To regenerate it after editing pkg/types/types.go, install easyjson and re-run codegen:

go install github.com/mailru/easyjson/easyjson@latest
go generate ./...

CI does this automatically on every run.

Cross-compile for a MIPS OpenWrt router:

CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat \
  go build -ldflags "-s -w -X main.Version=1.0.0" -o cake-stats-linux-mips ./cmd/cake-stats

Pre-built binaries for all common platforms are attached to every GitHub Release.

↑ Back to Table of Contents

Usage

Quick start

./cake-stats                 # serves on http://0.0.0.0:11112
./cake-stats -port 8080      # custom port
./cake-stats -interval 2s    # poll tc every 2 seconds (default 100ms)
./cake-stats -history 3600   # retain 1 hour of history (default 300 = 5 min)
./cake-stats -host 127.0.0.1 # listen only on loopback
./cake-stats -version        # print version and exit

Open http://<router-ip>:11112 in a browser.

Install on OpenWrt

sh install.sh                # auto-detects arch, downloads latest binary
sh install.sh --port 11112 --interval 1s

Note

The installer automatically enables and starts the init.d service. The OpenWrt init script is installed with START=99 so it comes up late in boot, registers with procd immediately, and waits through a brief overlay-mount race before exec-ing /usr/bin/cake-stats. A matching iface hotplug fallback also starts it later if netifd finishes after the rc.d boot window. The installer fails immediately if enable or start does not succeed. If you install by hand make sure to run:

/etc/init.d/cake-stats enable   # create the rc.d symlink
/etc/init.d/cake-stats start    # verify it launches immediately

To verify the router-side install after a reboot, copy verify-openwrt-install.sh to the router and run:

sh verify-openwrt-install.sh

Services that are not enabled will not start after a reboot.

Install on systemd Linux

sudo sh install.sh

Uninstall

sh uninstall.sh              # prompts for confirmation
sh uninstall.sh --force      # no prompts

API

Endpoint Description
GET / Web UI (HTML)
GET /api/stats Current stats snapshot (JSON)
GET /api/history Full ring-buffer history per interface (JSON), used to seed sparklines on page load
GET /events SSE stream — emits updated JSON on every poll interval

↑ Back to Table of Contents

Limitations & Next Steps

  • Still polls using tc; a kernel‑level rtnetlink watcher is included as an option but not yet the default.
  • No built‑in authentication or HTTPS; expose only on trusted networks or pair with a reverse proxy.
  • UI is intentionally minimal.
  • RAM footprint may vary. Depending on kernel malloc behaviour, architecture and how many clients are connected the value can be anywhere from about 4 MB up to a dozen megabytes.
  • Cross‑platform builds are produced, but CAKE itself is Linux‑only; Windows/FreeBSD binaries do not collect real data.

↑ Back to Table of Contents

Contributing

go test ./...    # run unit tests
go vet ./...     # static analysis

PRs welcome. Please keep external dependencies at zero.

↑ Back to Table of Contents

License

MIT

↑ Back to Table of Contents

About

Easily monitor CAKE SQM in real-time on OpenWrt or other Linux-based routers. Check YouTube link below for demo, simply use YouTube's Subtitles feature to auto-translate the video.

Topics

Resources

License

Stars

Watchers

Forks