feat: add usage stats parsing and fetching from /api/metrics/stats

This commit is contained in:
c4ch3c4d3
2026-08-14 12:47:53 -06:00
parent 7f877c4efb
commit 37f7268509
2 changed files with 85 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
import { type LlamaSwapConfig } from "./util";
export interface UsageStats {
totalRequests: number;
totalInputTokens: number;
totalOutputTokens: number;
genP95: number;
}
export function parseStats(json: unknown): UsageStats | null {
if (!json || typeof json !== "object") return null;
const obj = json as Record<string, unknown>;
const genHist = (obj.gen_histogram ?? {}) as Record<string, unknown>;
const num = (v: unknown): number => (typeof v === "number" && Number.isFinite(v) ? v : 0);
return {
totalRequests: num(obj.total_requests),
totalInputTokens: num(obj.total_input_tokens),
totalOutputTokens: num(obj.total_output_tokens),
genP95: num(genHist.p95),
};
}
export async function fetchStats(cfg: LlamaSwapConfig, modelId: string): Promise<UsageStats | null> {
const query = modelId === "all" ? "" : `?model=${encodeURIComponent(modelId)}`;
const headers: Record<string, string> = {};
if (cfg.apiKey) headers["Authorization"] = `Bearer ${cfg.apiKey}`;
const res = await fetch(`${cfg.baseUrl}/api/metrics/stats${query}`, {
headers,
signal: AbortSignal.timeout(5000),
});
if (!res.ok) return null;
return parseStats(await res.json());
}
+52
View File
@@ -0,0 +1,52 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { fetchStats, parseStats, type UsageStats } from "../src/lib/stats";
test("parseStats extracts totals and gen p95", () => {
const stats = parseStats({
total_requests: 1985,
total_input_tokens: 312327705,
total_output_tokens: 932710,
total_cache_tokens: 308144640,
gen_histogram: { p50: 341, p95: 378.86, p99: 392 },
});
assert.deepEqual(stats, { totalRequests: 1985, totalInputTokens: 312327705, totalOutputTokens: 932710, genP95: 378.86 });
});
test("parseStats defaults missing fields and rejects malformed input", () => {
assert.deepEqual(parseStats({}), { totalRequests: 0, totalInputTokens: 0, totalOutputTokens: 0, genP95: 0 });
assert.equal(parseStats({ total_requests: "nope" })!.totalRequests, 0);
assert.equal(parseStats(null), null);
assert.equal(parseStats("x"), null);
});
test("fetchStats calls /api/metrics/stats with a model query", async () => {
const calls: string[] = [];
const orig = globalThis.fetch;
globalThis.fetch = (async (url: RequestInfo | URL) => {
calls.push(String(url));
return { ok: true, json: async () => ({ total_requests: 7 }) } as unknown as Response;
}) as typeof fetch;
try {
await fetchStats({ baseUrl: "http://x" }, "DeepSeek-V4-Flash-0731");
assert.equal(calls[0], "http://x/api/metrics/stats?model=DeepSeek-V4-Flash-0731");
} finally {
globalThis.fetch = orig;
}
});
test("fetchStats omits the model query for 'all' and returns null on HTTP error", async () => {
const calls: string[] = [];
const orig = globalThis.fetch;
globalThis.fetch = (async (url: RequestInfo | URL) => {
calls.push(String(url));
return { ok: false, status: 500 } as unknown as Response;
}) as typeof fetch;
try {
const stats = await fetchStats({ baseUrl: "http://x" }, "all");
assert.equal(stats, null);
assert.equal(calls[0], "http://x/api/metrics/stats");
} finally {
globalThis.fetch = orig;
}
});