Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/commands/diagnose/metrics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, it, expect } from 'vitest';
import { formatValue } from './metrics.js';

describe('formatValue', () => {
it('formats disk byte counters as sizes, not percentages', () => {
expect(formatValue('disk_total', 8511270912)).toBe('7.9 GB');
expect(formatValue('disk_used', 1073741824)).toBe('1.0 GB');
expect(formatValue('disk_database', 5242880)).toBe('5.0 MB');
expect(formatValue('disk_wal', 2048)).toBe('2.0 KB');
expect(formatValue('disk_total', 2199023255552)).toBe('2.0 TB');
});

it('still formats percentage metrics with a percent sign', () => {
expect(formatValue('disk_usage', 42.1)).toBe('42.1%');
expect(formatValue('cpu_usage', 7)).toBe('7.0%');
expect(formatValue('memory_usage', 63.25)).toBe('63.3%');
});

it('formats network metrics as a rate', () => {
expect(formatValue('network_in', 512)).toBe('512.0 B/s');
expect(formatValue('network_out', 1536)).toBe('1.5 KB/s');
});
});
24 changes: 20 additions & 4 deletions src/commands/diagnose/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,39 @@ const METRIC_LABELS: Record<string, string> = {
cpu_usage: 'CPU Usage',
memory_usage: 'Memory Usage',
disk_usage: 'Disk Usage',
disk_used: 'Disk Used',
disk_total: 'Disk Total',
disk_database: 'Disk Database',
disk_wal: 'Disk WAL',
network_in: 'Network In',
network_out: 'Network Out',
};

const NETWORK_METRICS = new Set(['network_in', 'network_out']);

function formatValue(metric: string, value: number): string {
/** Raw byte counters — rendered as sizes, not percentages. */
const BYTE_METRICS = new Set(['disk_used', 'disk_total', 'disk_database', 'disk_wal']);

export function formatValue(metric: string, value: number): string {
if (NETWORK_METRICS.has(metric)) {
return formatBytes(value) + '/s';
}
if (BYTE_METRICS.has(metric)) {
return formatBytes(value);
}
return `${value.toFixed(1)}%`;
}

function formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes.toFixed(1)} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
const KB = 1024;
const MB = KB * 1024;
const GB = MB * 1024;
const TB = GB * 1024;
if (bytes < KB) return `${bytes.toFixed(1)} B`;
if (bytes < MB) return `${(bytes / KB).toFixed(1)} KB`;
if (bytes < GB) return `${(bytes / MB).toFixed(1)} MB`;
if (bytes < TB) return `${(bytes / GB).toFixed(1)} GB`;
return `${(bytes / TB).toFixed(1)} TB`;
}

function computeStats(data: MetricDataPoint[]): { latest: number; avg: number; max: number } {
Expand Down
Loading