Monitor usage and cache health
velodex counts everything it serves, off the request path. Four surfaces show the same numbers: the dashboard, the admin
status page, the /+stats JSON endpoint, and Prometheus /metrics.
Drill down from the dashboard
Each index card on the dashboard shows its pages, downloads, and bytes served, with a usage link. The link opens the
drill-down: totals for the index and a table of its projects, each project linking to its per-file counters. The same
pages live at /stats, /stats?index={route}, and /stats?index={route}&project={name}.
Query the counters
curl -s http://127.0.0.1:4433/+stats | jq
curl -s 'http://127.0.0.1:4433/+stats?index=root/pypi' | jq '.projects | to_entries | sort_by(-.value.downloads)[:5]'
curl -s 'http://127.0.0.1:4433/+stats?index=root/pypi&project=numpy' | jq .files
Counters live in memory and reset on restart; for durable time series, scrape /metrics, which exposes the same set per
index (velodex_index_downloads_total{index="root/pypi",ecosystem="pypi",role="virtual"} and friends) alongside the
global request counter.
Check operational status
/admin/status combines GET /+status?details=admin with top-level GET /+stats. It shows the configured index
topology next to the same cache-health counters listed below, plus observed project counts, upload counts, recent
uploads, cached index URLs, and redacted token/authentication state. The page does not fetch upstreams or read artifacts
while it renders.
What the cache-health counters mean
| Counter | Signal |
|---|---|
refreshes | Revalidations against upstream, on demand or from the background sweep |
changed | Revalidations that found new upstream content; also logged at info |
stale_served | Pages served from cache because upstream was down; rising means an outage |
upstream_errors | Upstream failures with nothing cached to fall back to; clients saw an error |
rejected | Downloads whose bytes did not match the advertised digest; never cached |
A steady refreshes with zero changed is the normal idle state. rejected above zero deserves attention: either the
upstream served corrupt bytes or something rewrote them in transit.
Inspect the disk cache
Use the cache CLI when you need the state on disk, not request counters.
velodex cache size --data-dir /var/lib/velodex
velodex cache list --data-dir /var/lib/velodex --stale
velodex cache fsck --data-dir /var/lib/velodex
cache size reports cached pages, stale pages, blob files, bytes, and metadata row counts. cache list --stale lists
the stale pages with age and freshness lifetime. cache fsck validates metadata row shapes and stream-hashes blob files
against their sha256 path.
Use two steps for project purge. First print the plan, then rerun with --yes if the row counts match what you expect.
velodex cache purge project --data-dir /var/lib/velodex --index pypi --project flask
velodex cache purge project --data-dir /var/lib/velodex --index pypi --project flask --yes
velodex cache purge orphaned-blobs --data-dir /var/lib/velodex
velodex cache purge orphaned-blobs --data-dir /var/lib/velodex --yes
Project purge removes metadata rows and leaves blobs in place. Orphaned-blob purge removes blob files that no metadata row references.
Related
- Where the counters come from: architecture
- The endpoint and counter reference: HTTP endpoints
- The counters in a browser: the web UI