UNPKG

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
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();