Pull requests / #2370
#2370 add lifetime useage statistics to monitoring
open · @wokhouse · 0 comentários · No GitHub
Server & APIAMD / HIPNVIDIA / CUDAModels & quantsDocumentationWindowsLinux
Descrição
Branch `pr/usage-stats` from `v0.1.43`. Commits: `1c612cec`, `df2aaf7a`, `f721c2ae`, and `64f426dc` (code), `66f4ab46` and `35557294` (docs).
Issue #2241 asks for this feature. The report there says:
> My Strata generated 150 million tokens… Strata doesn't have a total token count history that could be reset via, the session history also doesn't really add up things either?
Issue #35 (monitor totals only since boot) and PR #1707 (token analytics) are closed. #1707 added no persistent storage. No open pull request covers this.
## What it changes
The monitor's request history covers the current run only. The token analytics from #1707 keep no data across restarts. This pull request adds an opt-in counter store in `serve/usage.py`. It counts requests, prompt tokens read, prompt tokens reused, output tokens, prompt milliseconds, decode milliseconds, and MTP drafts offered and accepted. The store writes to a small JSON file next to the run config. The counters stay in that file after a restart.
The store holds counters only. It holds no prompts, no answers, and no request bodies.
- The feature is off by default. Set `"usage_stats": true` in `strata-<model>.json`, or add `--usage-stats` to `serve/server.py`.
- `GET /metrics` returns a `usage` object with lifetime totals and the `1d`, `7d`, and `30d` views.
- A custom range uses `?from_ts=<epoch>&to_ts=<epoch>`.
- The Usage panel in the monitor tab shows these views.
- The panel opens on the 7-day view. The view you pick is kept in the browser and restored on the next load. A Custom range comes back with its dates filled in. A stored value that is not a known view falls back to 7 days.
- The store keeps hourly buckets for 31 days. A custom range inside that window answers at hour resolution. A range that starts earlier is clamped to the oldest kept bucket. The panel reports the window it summed.
- The range buttons wrap on a narrow screen. A row that cannot wrap is 410px wide at its narrowest, and the monitor pane scrolls sideways instead of the buttons.
## What it leaves alone
This change touches no engine file. It changes Python and the web app only, so no CUDA, HIP, or SYCL rebuild is needed. No default changes. With the flag off, the usage code does nothing, no file is written, and `/metrics` reports `{"enabled": false}`. The Prometheus text output does not change.
## How I checked
- `serve/test_usage.py` is new and has 14 tests.
- The tests cover the off no-op, the counters, and persistence when the store reopens.
- They also cover recovery from a corrupt file, the four time views, and the custom range.
- The custom range tests cover the sum, the clamp, and an empty window.
- A second battery of 30 checks runs the store directly. It feeds wrongly typed counters, a clock that steps backwards, two writers at one time, an unwritable path, and odd ranges.
- I checked the HTTP layer against a live server. Empty, missing, and non-numeric range parameters return 200 and are ignored. A range outside the kept window is clamped to it.
- `serve.test_server` passes 296 of 296. `test_monitor` passes 10 of 10, `test_prometheus` 6 of 6, and `test_runconfig` 9 of 9.
- I checked the panel in a real browser. A fresh browser opens on 7 days. A pick survives a reload. A stored value that is not a view falls back to 7 days. A remembered Custom view comes back with its dates filled in.
- The browser checks cover the date picker too. A range that crosses a DST change sums the right window. An empty window reads differently from dates that were never set. Storage that throws, which private mode does, does not break the page.
- I checked the panel at phone widths: 320, 360, 390, 430, 540, and 768 px. The pane does not scroll sideways at any of them. The buttons wrap to three or four lines, and a press still works.
- The edge tests found four faults, and this branch fixes them. A hand-edited counters file stopped the server at boot. A clock that stepped backwards dropped a bucket from a view. The date prefill used the UTC day, so a user east of UTC saw the wrong window. A window with no data told the user to pick dates again.
- I checked the route against the mock engine. A request with no `from_ts` gets no custom view. A request with a valid range gets a window. Junk in the parameters is ignored. The range works with `?requests=all`.
- I put this build into production on my own box on 2026-10-13. The box runs Linux, an RTX 4090 with 24 GB, 60 GB RAM, and batch-1. It serves Qwen3.8-Flash-Next IQ3_S on engine 0.1.43. I read the counters file afterwards. It holds counters only.
## Not tested
Windows and the HIP path are untested here. This box runs Linux only. I did not test `--batch` or concurrency above 1. This box serves batch-1. This change adds no cost-per-token conversion. The counters are raw numbers, and no price table is added.
---
No site
Links install, modelos, releases.