Prometheus metrics for the daemon's state between requests (#194)

Logs and traces show requests, scans and downloads; nothing showed what
the daemon holds meanwhile. /metrics, behind sign-in, gives database
connections in use and idle against the pool's maximum, commands waiting
for the worker, live-update listeners, free torrent slots, episodes
playing through DeadAir, the library's counts, the tokio runtime's
workers, tasks and queue, and the process's memory and open files, in
Prometheus's text format, written by hand rather than with a client
library. Not logged or traced: Prometheus asks every 15 s. The iPX
dashboard gains a Daemon row of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 14:56:54 +00:00
parent b51df33bb6
commit 9fc1e7e248
7 changed files with 160 additions and 4 deletions

View File

@@ -1390,6 +1390,18 @@ test('/api/status gives a dashboard the counts, with the shared token as a cooki
expect(none.status()).toBe(401);
});
test('/metrics gives Prometheus the daemon\'s state, to someone signed in', async ({ page }) => {
const r = await page.request.get('/metrics', { headers: { cookie: `ipx_token=${TOKEN}` } });
expect(r.status()).toBe(200);
const text = await r.text();
// Every sample a name, optional labels and a number, as Prometheus parses them (#194).
for (const line of text.split('\n').filter(l => l && !l.startsWith('#')))
expect(line).toMatch(/^ipx_[a-z_]+(\{[^}]*\})? -?[0-9.e+]+$/);
for (const name of ['ipx_db_connections{state="in_use"}', 'ipx_db_connections_max', 'ipx_worker_queue', 'ipx_feeds', 'ipx_runtime_tasks', 'ipx_process_resident_bytes'])
expect(text).toContain(name);
expect((await page.request.get('/metrics', { headers: { cookie: '' } })).status()).toBe(401);
});
test('the favicon is the logo, square, from both pages', async ({ page }) => {
await page.evaluate(() => setTheme('modern', 'light'));
await expect(page.locator('#favicon')).toHaveAttribute('href', /^\/favicon\.png\?v=[0-9a-f]{12}$/);