bodhi-node-profiler
Version:
A lightweight, zero-configuration performance profiler for Node.js applications with real-time dashboard
159 lines (134 loc) • 4.29 kB
text/typescript
import chalk from 'chalk';
import ora from 'ora';
import clear from 'clear';
import figlet from 'figlet';
import { Command } from 'commander';
import Table from 'cli-table3';
import { BodhiProfiler } from './index';
import { Stats } from './types';
class ProfilerCLI {
private profiler: BodhiProfiler;
private refreshInterval: NodeJS.Timeout;
private spinner: any;
constructor() {
this.setupCLI();
}
private setupCLI() {
const program = new Command();
program
.version('1.0.3')
.description(chalk.cyan('Bodhi Node Profiler - Performance Monitoring Tool'));
program
.command('monitor')
.description('Start monitoring in terminal')
.option('-p, --port <number>', 'Dashboard port', '45678')
.option('-i, --interval <number>', 'Refresh interval in ms', '1000')
.option('-l, --log-path <string>', 'Log file path', './logs')
.action((options) => {
this.startMonitoring(options);
});
program
.command('dashboard')
.description('Start web dashboard')
.option('-p, --port <number>', 'Dashboard port', '45678')
.action((options) => {
this.startDashboard(options);
});
program.parse(process.argv);
}
private startMonitoring(options: any) {
clear();
console.log(
chalk.cyan(
figlet.textSync('Bodhi Profiler', { horizontalLayout: 'full' })
)
);
this.profiler = new BodhiProfiler({
port: parseInt(options.port),
logPath: options.logPath,
enableWebDashboard: true
});
this.spinner = ora('Starting monitoring...').start();
this.updateMetrics(parseInt(options.interval));
}
private updateMetrics(interval: number) {
this.refreshInterval = setInterval(() => {
const metrics = this.profiler.getStats();
this.displayMetrics(metrics);
}, interval);
}
private displayMetrics(metrics: Stats) {
clear();
// Header
console.log(chalk.cyan(
figlet.textSync('Bodhi Profiler', { horizontalLayout: 'full' })
));
// System Metrics Table
const systemTable = new Table({
head: [
chalk.cyan('Metric'),
chalk.cyan('Value'),
chalk.cyan('Status')
]
});
const cpuUsage = metrics.cpu.percentage;
const memoryUsage = (metrics.memory.heapUsed / metrics.memory.heapTotal) * 100;
systemTable.push(
[
'CPU Usage',
`${cpuUsage.toFixed(2)}%`,
this.getStatusIndicator(cpuUsage, 80)
],
[
'Memory Usage',
`${memoryUsage.toFixed(2)}%`,
this.getStatusIndicator(memoryUsage, 85)
],
[
'Event Loop Delay',
`${metrics.eventLoopDelay.toFixed(2)}ms`,
this.getStatusIndicator(metrics.eventLoopDelay, 100)
]
);
console.log(systemTable.toString());
// API Metrics
if (metrics.apiResponses && metrics.apiResponses.size > 0) {
const apiTable = new Table({
head: [
chalk.cyan('Endpoint'),
chalk.cyan('Response Time'),
chalk.cyan('Status')
]
});
metrics.apiResponses.forEach((duration: number, route: string) => {
apiTable.push([
route,
`${duration.toFixed(2)}ms`,
this.getStatusIndicator(duration, 1000)
]);
});
console.log('\nAPI Performance:');
console.log(apiTable.toString());
}
// Update timestamp
console.log(chalk.gray(`\nLast Updated: ${new Date().toLocaleTimeString()}`));
console.log(chalk.cyan(`\nDashboard: http://localhost:${this.profiler.options.port}/profiler/stats`));
}
private getStatusIndicator(value: number, threshold: number): string {
if (value > threshold) {
return chalk.red('⚠️ High');
} else if (value > threshold * 0.8) {
return chalk.yellow('⚠️ Warning');
}
return chalk.green('✓ Good');
}
private startDashboard(options: any) {
this.profiler = new BodhiProfiler({
port: parseInt(options.port),
enableWebDashboard: true
});
console.log(chalk.green('\n✓ Dashboard started successfully!'));
console.log(chalk.cyan(`\nAccess your dashboard at: http://localhost:${options.port}/profiler/stats`));
}
}
export default new ProfilerCLI();