feat(cli): Add stats CLI command and daemon stats aggregation; fix process manager & wrapper state handling
This commit is contained in:
66
ts/cli/commands/stats.ts
Normal file
66
ts/cli/commands/stats.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { tspmIpcClient } from '../../client/tspm.ipcclient.js';
|
||||
import type { CliArguments } from '../types.js';
|
||||
import { registerIpcCommand } from '../registration/index.js';
|
||||
import { pad } from '../helpers/formatting.js';
|
||||
import { formatMemory } from '../helpers/memory.js';
|
||||
|
||||
export function registerStatsCommand(smartcli: plugins.smartcli.Smartcli) {
|
||||
registerIpcCommand(
|
||||
smartcli,
|
||||
'stats',
|
||||
async (_argvArg: CliArguments) => {
|
||||
// Daemon status
|
||||
const status = await tspmIpcClient.request('daemon:status', {});
|
||||
|
||||
console.log('TSPM Daemon:');
|
||||
console.log('─'.repeat(60));
|
||||
console.log(`Version: ${status.version || 'unknown'}`);
|
||||
console.log(`PID: ${status.pid}`);
|
||||
console.log(`Uptime: ${Math.floor((status.uptime || 0) / 1000)}s`);
|
||||
console.log(`Processes: ${status.processCount}`);
|
||||
if (typeof status.memoryUsage === 'number') {
|
||||
console.log(`Memory: ${formatMemory(status.memoryUsage)}`);
|
||||
}
|
||||
if (typeof status.cpuUsage === 'number') {
|
||||
console.log(`CPU (user): ${status.cpuUsage.toFixed(3)}s`);
|
||||
}
|
||||
if ((status as any).paths) {
|
||||
const pathsInfo = (status as any).paths as { tspmDir?: string; socketPath?: string; pidFile?: string };
|
||||
console.log(`tspmDir: ${pathsInfo.tspmDir || '-'}`);
|
||||
console.log(`Socket: ${pathsInfo.socketPath || '-'}`);
|
||||
console.log(`PID File: ${pathsInfo.pidFile || '-'}`);
|
||||
}
|
||||
if ((status as any).configs) {
|
||||
const cfg = (status as any).configs as { processConfigs?: number };
|
||||
console.log(`Configs: ${cfg.processConfigs ?? 0}`);
|
||||
}
|
||||
if ((status as any).logsInMemory) {
|
||||
const lm = (status as any).logsInMemory as { totalCount: number; totalBytes: number };
|
||||
console.log(`Logs (mem): ${lm.totalCount} entries, ${formatMemory(lm.totalBytes)}`);
|
||||
}
|
||||
console.log('');
|
||||
|
||||
// Process list (reuse list view with CPU column)
|
||||
const response = await tspmIpcClient.request('list', {});
|
||||
const processes = response.processes;
|
||||
console.log('Process List:');
|
||||
console.log('┌─────────┬─────────────┬───────────┬───────────┬──────────┬──────────┬─────────┐');
|
||||
console.log('│ ID │ Name │ Status │ PID │ Memory │ CPU │ Restarts │');
|
||||
console.log('├─────────┼─────────────┼───────────┼───────────┼──────────┼──────────┼──────────┤');
|
||||
for (const proc of processes) {
|
||||
const statusColor =
|
||||
proc.status === 'online' ? '\x1b[32m' : proc.status === 'errored' ? '\x1b[31m' : '\x1b[33m';
|
||||
const resetColor = '\x1b[0m';
|
||||
const cpuStr = typeof proc.cpu === 'number' && isFinite(proc.cpu) ? `${proc.cpu.toFixed(1)}%` : '-';
|
||||
const nameDisplay = String(proc.id); // name not carried in IProcessInfo
|
||||
console.log(
|
||||
`│ ${pad(String(proc.id), 7)} │ ${pad(nameDisplay, 11)} │ ${statusColor}${pad(proc.status, 9)}${resetColor} │ ${pad((proc.pid || '-').toString(), 9)} │ ${pad(formatMemory(proc.memory), 8)} │ ${pad(cpuStr, 8)} │ ${pad(proc.restarts.toString(), 8)} │`,
|
||||
);
|
||||
}
|
||||
console.log('└─────────┴─────────────┴───────────┴───────────┴──────────┴──────────┴──────────┘');
|
||||
},
|
||||
{ actionLabel: 'get daemon stats' },
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user