fix(dashboard): real error rate from llm_api_errors_total

- errors now = rate(llm_api_errors_total) instead of network TX bytes
- rps = rate(llm_api_requests_total) + rate(http_server_request_count_total)
- Latency card → Load Average (was misleading: showed node load as 'ms')
- Overview 'Errors' StatBox was hardcoded 0 → real llm err/s
- rename hasTraffik → hasTraffic (Traefik removed 2026-08-02)
This commit is contained in:
asepharyana
2026-08-03 13:06:27 +07:00
parent 62966fd7cf
commit a90d0c4333
2 changed files with 37 additions and 17 deletions
+20 -8
View File
@@ -159,10 +159,10 @@ export async function GET() {
load15, load15,
netIn, netIn,
netOut, netOut,
rps, netInSpark,
latency, loadSpark,
errors, netOutSpark,
traceVolume, upstreamCount,
] = await Promise.all([ ] = await Promise.all([
promQuery( promQuery(
`100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)`, `100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)`,
@@ -184,6 +184,18 @@ export async function GET() {
promQuery("count(up)"), promQuery("count(up)"),
]); ]);
// ── Error rate (llm-api) & request rate (any /metrics service) ──
const [errRate, errSpark] = await Promise.all([
promQuery(`sum(rate(llm_api_errors_total[5m]))`),
promRange(`sum(rate(llm_api_errors_total[1m]))`),
]);
const reqRate = await promQuery(
`sum(rate(llm_api_requests_total[5m])) + sum(rate(http_server_request_count_total[5m]))`,
);
const reqSpark = await promRange(
`sum(rate(llm_api_requests_total[1m])) + sum(rate(http_server_request_count_total[1m]))`,
);
// ── LLM inference metrics (llm-api /metrics) ── // ── LLM inference metrics (llm-api /metrics) ──
const [ const [
llmReqRate, llmReqRate,
@@ -225,10 +237,10 @@ export async function GET() {
services, services,
traces: [], traces: [],
node: { cpu, ram, disk, load1, load5, load15, netIn, netOut }, node: { cpu, ram, disk, load1, load5, load15, netIn, netOut },
rps, rps: reqSpark,
latency, latency: loadSpark,
errors, errors: errSpark,
traceVolume: traceVolume ? [traceVolume] : [], traceVolume: netInSpark,
links, links,
llm: { llm: {
reqRate: llmReqRate, reqRate: llmReqRate,
+17 -9
View File
@@ -60,8 +60,8 @@ export default function Dashboard() {
data?.services.filter((s) => s.state === "running").length ?? 0; data?.services.filter((s) => s.state === "running").length ?? 0;
const degraded = (data?.services.length ?? 0) - running; const degraded = (data?.services.length ?? 0) - running;
const hasNode = data?.node.cpu !== null || data?.node.ram !== null; const hasNode = data?.node.cpu !== null || data?.node.ram !== null;
const hasTraffik = const hasTraffic =
(data?.rps?.length ?? 0) > 0 || (data?.latency?.length ?? 0) > 0; (data?.rps?.length ?? 0) > 0 || (data?.errors?.length ?? 0) > 0;
const node = data?.node; const node = data?.node;
return ( return (
@@ -147,7 +147,15 @@ export default function Dashboard() {
label="Traces" label="Traces"
color="text-blue-400" color="text-blue-400"
/> />
<StatBox value={0} label="Errors" color="text-red-400" /> <StatBox
value={
data?.errors?.length
? data.errors[data.errors.length - 1].toFixed(2)
: undefined
}
label="LLM err/s"
color="text-red-400"
/>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -299,7 +307,7 @@ export default function Dashboard() {
</motion.div> </motion.div>
{/* Request Rate */} {/* Request Rate */}
{hasTraffik && ( {hasTraffic && (
<motion.div variants={cardVariants}> <motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20"> <Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between"> <CardHeader className="flex flex-row items-center justify-between">
@@ -317,15 +325,15 @@ export default function Dashboard() {
</motion.div> </motion.div>
)} )}
{/* Latency */} {/* Load Average */}
{hasTraffik && ( {hasNode && (
<motion.div variants={cardVariants}> <motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20"> <Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between"> <CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Latency</CardTitle> <CardTitle>Load Average</CardTitle>
<Badge variant="secondary" className="text-[10px] font-normal"> <Badge variant="secondary" className="text-[10px] font-normal">
{data?.latency?.length {data?.latency?.length
? `${data.latency[data.latency.length - 1].toFixed(0)}ms` ? data.latency[data.latency.length - 1].toFixed(2)
: "-"} : "-"}
</Badge> </Badge>
</CardHeader> </CardHeader>
@@ -337,7 +345,7 @@ export default function Dashboard() {
)} )}
{/* Error Rate */} {/* Error Rate */}
{hasTraffik && ( {hasTraffic && (
<motion.div variants={cardVariants}> <motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20"> <Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between"> <CardHeader className="flex flex-row items-center justify-between">