README
¶
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
- Status
- Features
- Requirements
- Design Notes
- Build
- Usage
- Limitations & Next Steps
- Contributing
- License
How it looks like
Desktop
UI for desktop screens
Graphs for desktop screens
Mobile
UI for mobile screens
Graphs for mobile screens
Status
- Stable — all parser unit tests passing, binary builds clean for 14 target platforms. See Releases for the current version.
Features
- Automatically discovers all CAKE qdiscs via
tc -s qdisc, includingcake_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 separatefwmark MASKtin-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 (
#2D3C59bg, 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
-historyflag)
Requirements
- Linux kernel with
tc+sch_cakemodule loaded, or OpenWrt withkmod-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.gois checked in and generated via//go:generate easyjson -allinpkg/types/types.go. CI installs theeasyjsonbinary and re-runsgo 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)
Design Notes
- Modular architecture: code is split into
pkg/parser,pkg/history,pkg/server,pkg/log,pkg/types, andpkg/util, with the CLI entrypoint undercmd/cake-stats.pkg/utilcentralises all allocation-heavy string/byte helpers (split, trim, parse, zero-copy byte↔string conversions) so every other package imports one place instead of duplicatingstrconv/stringscall sites. This keeps the core logic reusable and simplifies testing. - Zero-allocation philosophy: hot paths avoid heap allocations by using
sync.Poolfor temporary buffers, easyjson-generated marshalers (MarshalEasyJSON/UnmarshalEasyJSONinpkg/types/types_easyjson.go) that skip reflection entirely, zero-copyunsafe-backed byte↔string conversions inpkg/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
tcinvocations. - 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, andpkg/utilinclude unit tests;pkg/historyalso includes a benchmark (BenchmarkHistoryRecord). Dependencies are kept to a minimum to ease audits.
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.gois checked in, so a normalgo buildworks without extra tools. To regenerate it after editingpkg/types/types.go, installeasyjsonand 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.
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
[!TIP] The installer automatically enables and starts the init.d service.
The OpenWrt init script is installed with
START=99so it comes up late in boot, registers with procd immediately, and waits through a brief overlay-mount race beforeexec-ing/usr/bin/cake-stats. A matchingifacehotplug fallback also starts it later if netifd finishes after the rc.d boot window. The installer fails immediately ifenableorstartdoes 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 immediatelyTo verify the router-side install after a reboot, copy
verify-openwrt-install.shto the router and run:sh verify-openwrt-install.shServices that are not enabled will not start after a reboot.
[!NOTE] OpenWrt notes from community feedback:
- If you plan to install on-router using
git clone, many OpenWrt builds ship a minimalgitwithout HTTPS support. Replace it withgit-httpand install the CA bundle to enable HTTPS access to GitHub:opkg update opkg remove git opkg install git-http ca-bundle
git-httpprovides HTTPS-capablegitandca-bundlesupplies root certificates required to verify GitHub (or other HTTPS) hosts.
- Some OpenWrt images include a trimmed
wgetthat does not support the--show-progressoption. Ifsh install.shfails withwget: unrecognized option: show-progress, either editinstall.shto remove the--show-progressflag, or install a fullwget/curlpackage on the router before running the installer:opkg install wget curl # or edit install.sh and remove the --show-progress argumentAlternatively, download a prebuilt binary from the Releases page and copy it to
/usr/binon the router.
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 |
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.
Contributing
go test ./... # run unit tests
go vet ./... # static analysis
PRs welcome. Please keep external dependencies at zero.
License
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
cake-stats
command
|
|
|
pkg
|
|
|
util
Package util provides shared, allocation-minimising string and byte- conversion helpers used across multiple packages in cake-stats.
|
Package util provides shared, allocation-minimising string and byte- conversion helpers used across multiple packages in cake-stats. |