Fix frontend/backend type mismatches in monitoring

TypeScript types now match Go backend JSON field names:
- MemoryStats: used_bytes, total_bytes, usage_percent, heap_alloc, heap_sys, heap_inuse
- DiskStats: used_bytes, total_bytes, free_bytes, usage_percent
- RuntimeStats: num_gc, last_gc_pause_ns
- HTTPStats: requests_total, requests_per_minute
- EndpointStats: error_rate (ratio), p95_latency_ms
- AsynqStats: removed total_* aggregates (calculated in frontend)

Updated components to use correct field names and calculate
aggregates where needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-09 10:56:47 -06:00
parent eb127fda20
commit 3f2b5415ed
4 changed files with 66 additions and 68 deletions

View File

@@ -41,9 +41,9 @@ export function HTTPStatsOverview({ stats }: HTTPStatsProps) {
<Activity className="h-4 w-4 text-muted-foreground" /> <Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{(stats.total_requests ?? 0).toLocaleString()}</div> <div className="text-2xl font-bold">{(stats.requests_total ?? 0).toLocaleString()}</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{(stats.requests_per_second ?? 0).toFixed(2)} req/s {(stats.requests_per_minute ?? 0).toFixed(2)} req/min
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@@ -55,9 +55,6 @@ export function HTTPStatsOverview({ stats }: HTTPStatsProps) {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{formatLatency(stats.avg_latency_ms)}</div> <div className="text-2xl font-bold">{formatLatency(stats.avg_latency_ms)}</div>
<p className="text-xs text-muted-foreground">
P95: {formatLatency(stats.p95_latency_ms)}
</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -67,10 +64,7 @@ export function HTTPStatsOverview({ stats }: HTTPStatsProps) {
<AlertTriangle className="h-4 w-4 text-muted-foreground" /> <AlertTriangle className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{formatPercent(stats.error_rate)}</div> <div className="text-2xl font-bold">{formatPercent((stats.error_rate ?? 0) * 100)}</div>
<p className="text-xs text-muted-foreground">
{(stats.errors_total ?? 0).toLocaleString()} total errors
</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -80,8 +74,8 @@ export function HTTPStatsOverview({ stats }: HTTPStatsProps) {
<Gauge className="h-4 w-4 text-muted-foreground" /> <Gauge className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{(stats.requests_per_second ?? 0).toFixed(2)}</div> <div className="text-2xl font-bold">{(stats.requests_per_minute ?? 0).toFixed(2)}</div>
<p className="text-xs text-muted-foreground">requests per second</p> <p className="text-xs text-muted-foreground">requests per minute</p>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
@@ -121,22 +115,22 @@ export function HTTPEndpointStats({ stats }: HTTPStatsProps) {
<TableHead>Endpoint</TableHead> <TableHead>Endpoint</TableHead>
<TableHead className="text-right">Requests</TableHead> <TableHead className="text-right">Requests</TableHead>
<TableHead className="text-right">Avg Latency</TableHead> <TableHead className="text-right">Avg Latency</TableHead>
<TableHead className="text-right">Errors</TableHead> <TableHead className="text-right">P95 Latency</TableHead>
<TableHead className="text-right">Error Rate</TableHead> <TableHead className="text-right">Error Rate</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{sortedEndpoints.map(([endpoint, data]) => { {sortedEndpoints.map(([endpoint, data]) => {
const errorRate = data.count > 0 ? (data.errors / data.count) * 100 : 0; const errorRatePercent = (data.error_rate ?? 0) * 100;
return ( return (
<TableRow key={endpoint}> <TableRow key={endpoint}>
<TableCell className="font-mono text-sm">{endpoint}</TableCell> <TableCell className="font-mono text-sm">{endpoint}</TableCell>
<TableCell className="text-right">{data.count.toLocaleString()}</TableCell> <TableCell className="text-right">{data.count.toLocaleString()}</TableCell>
<TableCell className="text-right">{formatLatency(data.avg_latency_ms)}</TableCell> <TableCell className="text-right">{formatLatency(data.avg_latency_ms)}</TableCell>
<TableCell className="text-right">{data.errors}</TableCell> <TableCell className="text-right">{formatLatency(data.p95_latency_ms)}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<span className={errorRate > 5 ? 'text-red-500' : ''}> <span className={errorRatePercent > 5 ? 'text-red-500' : ''}>
{formatPercent(errorRate)} {formatPercent(errorRatePercent)}
</span> </span>
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@@ -18,7 +18,7 @@ interface QueueStatsProps {
} }
export function QueueOverview({ stats }: QueueStatsProps) { export function QueueOverview({ stats }: QueueStatsProps) {
if (!stats) { if (!stats || !stats.queues) {
return ( return (
<Card> <Card>
<CardHeader> <CardHeader>
@@ -33,6 +33,18 @@ export function QueueOverview({ stats }: QueueStatsProps) {
); );
} }
// Calculate totals from individual queues
const totals = Object.values(stats.queues).reduce(
(acc, queue) => ({
pending: acc.pending + (queue.pending ?? 0),
active: acc.active + (queue.active ?? 0),
scheduled: acc.scheduled + (queue.scheduled ?? 0),
retry: acc.retry + (queue.retry ?? 0),
failed: acc.failed + (queue.failed ?? 0),
}),
{ pending: 0, active: 0, scheduled: 0, retry: 0, failed: 0 }
);
return ( return (
<div className="grid gap-4 md:grid-cols-5"> <div className="grid gap-4 md:grid-cols-5">
<Card> <Card>
@@ -41,7 +53,7 @@ export function QueueOverview({ stats }: QueueStatsProps) {
<Clock className="h-4 w-4 text-muted-foreground" /> <Clock className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.total_pending}</div> <div className="text-2xl font-bold">{totals.pending}</div>
<p className="text-xs text-muted-foreground">tasks waiting</p> <p className="text-xs text-muted-foreground">tasks waiting</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -52,7 +64,7 @@ export function QueueOverview({ stats }: QueueStatsProps) {
<PlayCircle className="h-4 w-4 text-blue-500" /> <PlayCircle className="h-4 w-4 text-blue-500" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold text-blue-500">{stats.total_active}</div> <div className="text-2xl font-bold text-blue-500">{totals.active}</div>
<p className="text-xs text-muted-foreground">currently running</p> <p className="text-xs text-muted-foreground">currently running</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -63,7 +75,7 @@ export function QueueOverview({ stats }: QueueStatsProps) {
<Clock className="h-4 w-4 text-muted-foreground" /> <Clock className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.total_scheduled}</div> <div className="text-2xl font-bold">{totals.scheduled}</div>
<p className="text-xs text-muted-foreground">future tasks</p> <p className="text-xs text-muted-foreground">future tasks</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -74,7 +86,7 @@ export function QueueOverview({ stats }: QueueStatsProps) {
<RotateCcw className="h-4 w-4 text-yellow-500" /> <RotateCcw className="h-4 w-4 text-yellow-500" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold text-yellow-500">{stats.total_retry}</div> <div className="text-2xl font-bold text-yellow-500">{totals.retry}</div>
<p className="text-xs text-muted-foreground">awaiting retry</p> <p className="text-xs text-muted-foreground">awaiting retry</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -85,7 +97,7 @@ export function QueueOverview({ stats }: QueueStatsProps) {
<AlertTriangle className="h-4 w-4 text-red-500" /> <AlertTriangle className="h-4 w-4 text-red-500" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold text-red-500">{stats.total_failed}</div> <div className="text-2xl font-bold text-red-500">{totals.failed}</div>
<p className="text-xs text-muted-foreground">permanently failed</p> <p className="text-xs text-muted-foreground">permanently failed</p>
</CardContent> </CardContent>
</Card> </Card>
@@ -143,7 +155,6 @@ export function QueueDetails({ stats }: QueueStatsProps) {
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Queue</TableHead> <TableHead>Queue</TableHead>
<TableHead className="text-right">Size</TableHead>
<TableHead className="text-right">Pending</TableHead> <TableHead className="text-right">Pending</TableHead>
<TableHead className="text-right">Active</TableHead> <TableHead className="text-right">Active</TableHead>
<TableHead className="text-right">Scheduled</TableHead> <TableHead className="text-right">Scheduled</TableHead>
@@ -157,26 +168,25 @@ export function QueueDetails({ stats }: QueueStatsProps) {
{sortedQueues.map(([queueName, queue]) => ( {sortedQueues.map(([queueName, queue]) => (
<TableRow key={queueName}> <TableRow key={queueName}>
<TableCell>{getPriorityBadge(queueName)}</TableCell> <TableCell>{getPriorityBadge(queueName)}</TableCell>
<TableCell className="text-right">{queue.size}</TableCell> <TableCell className="text-right">{queue.pending ?? 0}</TableCell>
<TableCell className="text-right">{queue.pending}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<span className={queue.active > 0 ? 'text-blue-500 font-medium' : ''}> <span className={(queue.active ?? 0) > 0 ? 'text-blue-500 font-medium' : ''}>
{queue.active} {queue.active ?? 0}
</span> </span>
</TableCell> </TableCell>
<TableCell className="text-right">{queue.scheduled}</TableCell> <TableCell className="text-right">{queue.scheduled ?? 0}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<span className={queue.retry > 0 ? 'text-yellow-500' : ''}> <span className={(queue.retry ?? 0) > 0 ? 'text-yellow-500' : ''}>
{queue.retry} {queue.retry ?? 0}
</span> </span>
</TableCell> </TableCell>
<TableCell className="text-right">{queue.archived}</TableCell> <TableCell className="text-right">{queue.archived ?? 0}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<span className="text-green-500">{queue.completed}</span> <span className="text-green-500">{queue.completed ?? 0}</span>
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<span className={queue.failed > 0 ? 'text-red-500 font-medium' : ''}> <span className={(queue.failed ?? 0) > 0 ? 'text-red-500 font-medium' : ''}>
{queue.failed} {queue.failed ?? 0}
</span> </span>
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@@ -35,9 +35,9 @@ function ProcessCard({ stats, title }: ProcessCardProps) {
<div className="space-y-1"> <div className="space-y-1">
<div className="flex items-center gap-1 text-xs text-muted-foreground"> <div className="flex items-center gap-1 text-xs text-muted-foreground">
<Server className="h-3 w-3" /> <Server className="h-3 w-3" />
Memory Go Heap
</div> </div>
<p className="text-lg font-semibold">{formatBytes(stats.memory?.go_alloc)}</p> <p className="text-lg font-semibold">{formatBytes(stats.memory?.heap_alloc)}</p>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<div className="flex items-center gap-1 text-xs text-muted-foreground"> <div className="flex items-center gap-1 text-xs text-muted-foreground">
@@ -122,9 +122,9 @@ export function SystemOverview({ apiStats, workerStats }: SystemOverviewProps) {
<Server className="h-4 w-4 text-muted-foreground" /> <Server className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{formatPercent(stats.memory?.system_percent)}</div> <div className="text-2xl font-bold">{formatPercent(stats.memory?.usage_percent)}</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{formatBytes(stats.memory?.system_used)} / {formatBytes(stats.memory?.system_total)} {formatBytes(stats.memory?.used_bytes)} / {formatBytes(stats.memory?.total_bytes)}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@@ -135,9 +135,9 @@ export function SystemOverview({ apiStats, workerStats }: SystemOverviewProps) {
<HardDrive className="h-4 w-4 text-muted-foreground" /> <HardDrive className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{formatPercent(stats.disk?.percent)}</div> <div className="text-2xl font-bold">{formatPercent(stats.disk?.usage_percent)}</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{formatBytes(stats.disk?.used)} / {formatBytes(stats.disk?.total)} {formatBytes(stats.disk?.used_bytes)} / {formatBytes(stats.disk?.total_bytes)}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@@ -148,9 +148,9 @@ export function SystemOverview({ apiStats, workerStats }: SystemOverviewProps) {
<Zap className="h-4 w-4 text-muted-foreground" /> <Zap className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{(apiStats?.runtime.gc_runs || 0) + (workerStats?.runtime.gc_runs || 0)}</div> <div className="text-2xl font-bold">{(apiStats?.runtime?.num_gc || 0) + (workerStats?.runtime?.num_gc || 0)}</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Total pause: {((apiStats?.runtime.gc_pause_total_ns || 0) + (workerStats?.runtime.gc_pause_total_ns || 0)) / 1000000}ms Last pause: {safeToFixed(((apiStats?.runtime?.last_gc_pause_ns || 0) + (workerStats?.runtime?.last_gc_pause_ns || 0)) / 1000000)}ms
</p> </p>
</CardContent> </CardContent>
</Card> </Card>

View File

@@ -12,55 +12,54 @@ export interface LogEntry {
export interface CPUStats { export interface CPUStats {
usage_percent: number; usage_percent: number;
num_cpu: number;
load_avg_1: number; load_avg_1: number;
load_avg_5: number; load_avg_5: number;
load_avg_15: number; load_avg_15: number;
} }
export interface MemoryStats { export interface MemoryStats {
system_total: number; // System memory
system_used: number; used_bytes: number;
system_percent: number; total_bytes: number;
go_alloc: number; usage_percent: number;
go_total_alloc: number; // Go heap
go_sys: number; heap_alloc: number;
go_heap_alloc: number; heap_sys: number;
go_heap_sys: number; heap_inuse: number;
} }
export interface DiskStats { export interface DiskStats {
total: number; used_bytes: number;
used: number; total_bytes: number;
percent: number; free_bytes: number;
usage_percent: number;
} }
export interface RuntimeStats { export interface RuntimeStats {
goroutines: number; goroutines: number;
gc_runs: number; num_gc: number;
gc_pause_ns: number; last_gc_pause_ns: number;
gc_pause_total_ns: number;
uptime_seconds: number; uptime_seconds: number;
} }
export interface EndpointStats { export interface EndpointStats {
count: number; count: number;
total_latency_ms: number;
avg_latency_ms: number; avg_latency_ms: number;
errors: number; p95_latency_ms: number;
error_rate: number;
} }
export interface HTTPStats { export interface HTTPStats {
total_requests: number; requests_total: number;
requests_per_second: number; requests_per_minute: number;
avg_latency_ms: number; avg_latency_ms: number;
p95_latency_ms: number;
errors_total: number;
error_rate: number; error_rate: number;
by_endpoint: Record<string, EndpointStats>; by_endpoint: Record<string, EndpointStats>;
by_status_code: Record<number, number>;
} }
export interface QueueStats { export interface QueueStats {
size: number;
pending: number; pending: number;
active: number; active: number;
scheduled: number; scheduled: number;
@@ -72,11 +71,6 @@ export interface QueueStats {
export interface AsynqStats { export interface AsynqStats {
queues: Record<string, QueueStats>; queues: Record<string, QueueStats>;
total_pending: number;
total_active: number;
total_scheduled: number;
total_retry: number;
total_failed: number;
} }
export interface SystemStats { export interface SystemStats {