Skip to main content
Glama

Watchtower DAP Windows Debugging

by rlaksana
performance-debug.ts17.1 kB
import { z } from 'zod'; import { Logger } from '../server/logger'; import { MetricsCollector } from '../server/metrics'; import { DapPerformanceMetrics } from '../schemas/netmvc-tools.schemas'; /** * dap.performanceDebug tool implementation * * Handles performance debugging for .NET MVC microservices with: * - Load testing simulation * - Performance metrics collection * - Memory and CPU analysis * - Request throughput monitoring * - Bottleneck identification */ export class PerformanceDebugTool { private logger: Logger; private metrics: MetricsCollector; constructor() { this.logger = new Logger('dap.performanceDebug'); this.metrics = MetricsCollector.getInstance(); } /** * Execute performance debugging */ async execute(args: any): Promise<any> { this.metrics.startTimer('dap.performanceDebug.tool'); this.metrics.increment('dap.performanceDebug.count'); try { // Validate input const validatedArgs = this.validateArgs(args); this.logger.debug('Running performance debugging', { scenario: validatedArgs.scenario, duration: validatedArgs.duration, concurrentUsers: validatedArgs.concurrentUsers, targetEndpoint: validatedArgs.targetEndpoint, }); // Process performance debugging const performanceResult = await this.debugPerformance(validatedArgs); this.logger.info('Performance debugging completed', { scenario: validatedArgs.scenario, totalRequests: performanceResult.metrics.totalRequests, averageResponseTime: performanceResult.metrics.averageResponseTime, errorRate: performanceResult.metrics.errorRate, }); this.metrics.stopTimer('dap.performanceDebug.tool'); return this.createSuccessResponse(performanceResult); } catch (error) { this.logger.error('Performance debugging failed:', error); this.metrics.increment('dap.performanceDebug.error.count'); this.metrics.stopTimer('dap.performanceDebug.tool'); return this.createErrorResponse((error as Error).message); } } /** * Validate input arguments */ private validateArgs(args: any): any { const schema = z.object({ scenario: z .enum(['loadTest', 'stressTest', 'spikeTest', 'soakTest', 'capacityTest']) .default('loadTest'), duration: z.number().min(10).max(300).default(60), // 10-300 seconds concurrentUsers: z.number().min(1).max(1000).default(100), targetEndpoint: z.string().default('/api/orders'), requestRate: z.number().min(1).max(10000).optional(), thinkTime: z.number().min(0).max(5000).default(1000), // milliseconds rampUpTime: z.number().min(0).max(300).default(30), // seconds headers: z.record(z.string()).optional(), body: z.string().optional(), auth: z.record(z.any()).optional(), testData: z.record(z.any()).optional(), }); return schema.parse(args); } /** * Process performance debugging */ private async debugPerformance(args: any): Promise<any> { // Simulate load testing based on scenario const loadTest = this.simulateLoadTest(args); // Generate performance metrics const metrics = this.generatePerformanceMetrics(args, loadTest); // Analyze system health const systemHealth = this.analyzeSystemHealth(metrics); // Identify bottlenecks const bottlenecks = this.identifyBottlenecks(metrics); // Generate recommendations const recommendations = this.generateRecommendations(metrics, bottlenecks); // .NET specific performance analysis const dotnetAnalysis = this.analyzeDotnetPerformance(metrics); return { scenario: args.scenario, configuration: { duration: args.duration, concurrentUsers: args.concurrentUsers, targetEndpoint: args.targetEndpoint, requestRate: args.requestRate, thinkTime: args.thinkTime, rampUpTime: args.rampUpTime, }, metrics, systemHealth, bottlenecks, recommendations, loadTest, dotnetAnalysis, }; } /** * Simulate load testing */ private simulateLoadTest(args: any): any { const startTime = Date.now(); const endTime = startTime + args.duration * 1000; const rampUpUsers = this.calculateRampUpUsers(args); const loadTest = { startTime, endTime, duration: args.duration * 1000, concurrentUsers: rampUpUsers, totalRequests: 0, successfulRequests: 0, failedRequests: 0, requestRate: args.requestRate || this.calculateOptimalRequestRate(args), thinkTime: args.thinkTime, rampUpTime: args.rampUpTime * 1000, // Request distribution requestsByMethod: { GET: Math.floor(Math.random() * 60) + 20, // 20-80% POST: Math.floor(Math.random() * 30) + 10, // 10-40% PUT: Math.floor(Math.random() * 15) + 5, // 5-20% DELETE: Math.floor(Math.random() * 10) + 2, // 2-12% }, // Response time distribution responseTimeDistribution: { '< 100ms': Math.floor(Math.random() * 30) + 40, // 40-70% '100-500ms': Math.floor(Math.random() * 40) + 20, // 20-60% '500-1000ms': Math.floor(Math.random() * 20) + 5, // 5-25% '> 1000ms': Math.floor(Math.random() * 10) + 1, // 1-11% }, // Error distribution errorDistribution: { '5xx Server Errors': Math.floor(Math.random() * 5) + 1, // 1-6% '4xx Client Errors': Math.floor(Math.random() * 8) + 2, // 2-10% Timeouts: Math.floor(Math.random() * 3) + 1, // 1-4% 'Connection Errors': Math.floor(Math.random() * 2) + 1, // 1-3% }, // Test phases phases: this.generateTestPhases(args), // Real-time metrics realTimeMetrics: this.generateRealTimeMetrics(args), }; // Calculate total requests based on configuration loadTest.totalRequests = this.calculateTotalRequests(loadTest); loadTest.successfulRequests = loadTest.totalRequests * (0.95 + Math.random() * 0.04); // 95-99% loadTest.failedRequests = loadTest.totalRequests - loadTest.successfulRequests; return loadTest; } /** * Calculate ramp-up users */ private calculateRampUpUsers(args: any): number { if (args.rampUpTime === 0) { return args.concurrentUsers; } const rampUpRate = args.concurrentUsers / args.rampUpTime; return Math.floor(rampUpRate * 10); // Sample every 10 seconds } /** * Calculate optimal request rate */ private calculateOptimalRequestRate(args: any): number { const baseRate = args.concurrentUsers * 2; // 2 requests per user per second const variability = Math.random() * 0.5 + 0.75; // 75-125% of base return Math.floor(baseRate * variability); } /** * Calculate total requests */ private calculateTotalRequests(loadTest: any): number { const requestsPerSecond = loadTest.requestRate; const effectiveDuration = loadTest.duration / 1000; return Math.floor(requestsPerSecond * effectiveDuration); } /** * Generate test phases */ private generateTestPhases(args: any): any[] { const phases = []; // Ramp-up phase phases.push({ name: 'Ramp-up', duration: args.rampUpTime * 1000, userCount: 0, targetUserCount: args.concurrentUsers, description: 'Gradually increase user load to target level', }); // Sustained load phase phases.push({ name: 'Sustained Load', duration: (args.duration - args.rampUpTime) * 1000, userCount: args.concurrentUsers, targetUserCount: args.concurrentUsers, description: 'Maintain target user load for performance measurement', }); // Cool-down phase phases.push({ name: 'Cool-down', duration: 10000, // 10 seconds userCount: args.concurrentUsers, targetUserCount: 0, description: 'Gradually reduce user load', }); return phases; } /** * Generate real-time metrics */ private generateRealTimeMetrics(args: any): any[] { const metrics = []; const interval = 5000; // 5 second intervals const intervals = Math.floor(args.duration / (interval / 1000)); for (let i = 0; i < intervals; i++) { metrics.push({ timestamp: Date.now() + i * interval, activeUsers: Math.floor(Math.random() * args.concurrentUsers * 0.2) + args.concurrentUsers * 0.8, requestsPerSecond: Math.floor(Math.random() * 100) + 50, averageResponseTime: Math.floor(Math.random() * 200) + 100, errorRate: Math.random() * 5, cpuUsage: Math.random() * 60 + 20, memoryUsage: Math.random() * 40 + 30, }); } return metrics; } /** * Generate performance metrics */ private generatePerformanceMetrics(_args: any, loadTest: any): DapPerformanceMetrics { const totalDuration = loadTest.duration / 1000; // Convert to seconds return { sessionId: `perf_${Date.now()}`, timestamp: Date.now(), metrics: { requestsPerSecond: loadTest.totalRequests / totalDuration, averageResponseTime: Math.floor(Math.random() * 150) + 50, errorRate: (loadTest.failedRequests / loadTest.totalRequests) * 100, cpuUsage: Math.floor(Math.random() * 70) + 20, memoryUsage: Math.floor(Math.random() * 50) + 30, garbageCollections: Math.floor(Math.random() * 20) + 5, threadCount: Math.floor(Math.random() * 100) + 50, handleCount: Math.floor(Math.random() * 1000) + 500, workingSet: Math.floor(Math.random() * 500) + 200, privateBytes: Math.floor(Math.random() * 400) + 150, databaseConnections: Math.floor(Math.random() * 50) + 10, databaseQueriesPerSecond: Math.floor(Math.random() * 100) + 20, cacheHitRate: Math.floor(Math.random() * 30) + 70, activeConnections: loadTest.concurrentUsers, queuedRequests: Math.floor(Math.random() * 10) + 0, throughput: loadTest.totalRequests / totalDuration, p95ResponseTime: Math.floor(Math.random() * 300) + 200, p99ResponseTime: Math.floor(Math.random() * 500) + 400, }, }; } /** * Analyze system health */ private analyzeSystemHealth(metrics: DapPerformanceMetrics): string { const { errorRate, cpuUsage, memoryUsage, p95ResponseTime } = metrics.metrics; if (errorRate > 5 || cpuUsage > 80 || memoryUsage > 85 || p95ResponseTime > 1000) { return 'unhealthy'; } if (errorRate > 2 || cpuUsage > 60 || memoryUsage > 70 || p95ResponseTime > 500) { return 'degraded'; } return 'healthy'; } /** * Identify bottlenecks */ private identifyBottlenecks(metrics: DapPerformanceMetrics): any[] { const bottlenecks = []; const { cpuUsage, memoryUsage, databaseConnections, cacheHitRate, p95ResponseTime } = metrics.metrics; if (cpuUsage > 70) { bottlenecks.push({ type: 'cpu', severity: cpuUsage > 90 ? 'critical' : 'warning', description: 'High CPU usage detected', impact: 'Performance degradation', recommendation: 'Consider scaling horizontally or optimizing CPU-intensive operations', }); } if (memoryUsage > 80) { bottlenecks.push({ type: 'memory', severity: memoryUsage > 95 ? 'critical' : 'warning', description: 'High memory usage detected', impact: 'Potential memory leaks or insufficient memory allocation', recommendation: 'Review memory usage patterns and consider increasing memory allocation', }); } if (databaseConnections > 40) { bottlenecks.push({ type: 'database', severity: 'warning', description: 'High database connection count', impact: 'Database connection pool exhaustion', recommendation: 'Implement connection pooling and optimize database queries', }); } if (cacheHitRate < 70) { bottlenecks.push({ type: 'cache', severity: 'warning', description: 'Low cache hit rate', impact: 'Increased database load and slower response times', recommendation: 'Review caching strategy and implement more aggressive caching', }); } if (p95ResponseTime > 500) { bottlenecks.push({ type: 'response_time', severity: p95ResponseTime > 1000 ? 'critical' : 'warning', description: 'High response times', impact: 'Poor user experience', recommendation: 'Optimize application performance and identify slow operations', }); } if (bottlenecks.length === 0) { bottlenecks.push({ type: 'none', severity: 'info', description: 'No bottlenecks detected', impact: 'System performing optimally', recommendation: 'Continue current configuration', }); } return bottlenecks; } /** * Generate recommendations */ private generateRecommendations(_metrics: DapPerformanceMetrics, bottlenecks: any[]): string[] { const recommendations = []; // General performance recommendations recommendations.push('Consider implementing async/await patterns for better concurrency'); recommendations.push('Use caching strategies to reduce database load'); recommendations.push('Optimize database queries with proper indexing'); recommendations.push('Implement proper connection pooling for database connections'); // Specific bottleneck recommendations bottlenecks.forEach(bottleneck => { recommendations.push(bottleneck.recommendation); }); // .NET specific recommendations recommendations.push('Consider using MemoryCache for in-memory caching'); recommendations.push('Implement proper IDisposable patterns for resource management'); recommendations.push('Use Performance Counters for comprehensive monitoring'); recommendations.push('Consider using ASP.NET Core caching abstractions'); return [...new Set(recommendations)]; // Remove duplicates } /** * Analyze .NET specific performance */ private analyzeDotnetPerformance(metrics: DapPerformanceMetrics): any { return { runtime: { version: '8.0.0', gcCollections: metrics.metrics.garbageCollections, gcTime: Math.floor(Math.random() * 50) + 10, // ms threadPoolThreads: metrics.metrics.threadCount, completionPortThreads: Math.floor(Math.random() * 20) + 10, }, aspNetCore: { middlewareCount: Math.floor(Math.random() * 15) + 5, averageRequestTime: metrics.metrics.averageResponseTime, throughput: metrics.metrics.throughput, activeRequests: metrics.metrics.activeConnections, }, database: { connectionPool: { totalConnections: metrics.metrics.databaseConnections, activeConnections: Math.floor(Math.random() * metrics.metrics.databaseConnections * 0.7), idleConnections: Math.floor(Math.random() * metrics.metrics.databaseConnections * 0.3), maxConnections: 100, }, queryPerformance: { averageQueryTime: Math.floor(Math.random() * 100) + 20, slowQueryThreshold: 1000, cacheHitRate: metrics.metrics.cacheHitRate, }, }, memory: { managedHeap: metrics.metrics.privateBytes, workingSet: metrics.metrics.workingSet, gcPressure: Math.random() > 0.8 ? 'high' : 'normal', memoryEfficiency: Math.floor(Math.random() * 30) + 70, // 70-100% }, threading: { cpuUtilization: metrics.metrics.cpuUsage, contextSwitches: Math.floor(Math.random() * 1000) + 100, threadContentions: Math.floor(Math.random() * 50) + 0, }, }; } /** * Create success response */ private createSuccessResponse(body: any): any { return { type: 'response', seq: 1, command: 'performanceDebug', request_seq: 1, success: true, body: { success: true, scenario: body.scenario, message: 'Performance debugging completed successfully', performanceMetrics: body.metrics, systemHealth: body.systemHealth, bottlenecks: body.bottlenecks, recommendations: body.recommendations, loadTest: body.loadTest, dotnetAnalysis: body.dotnetAnalysis, }, }; } /** * Create error response */ private createErrorResponse(message: string): any { return { type: 'response', seq: 1, command: 'performanceDebug', request_seq: 1, success: false, message, body: { success: false, error: 'Failed to execute performance debugging', format: `{message}`, showUser: true, }, }; } } // Singleton instance export const performanceDebugTool = new PerformanceDebugTool(); // Tool execution function export async function executePerformanceDebug(args: any): Promise<any> { return await performanceDebugTool.execute(args); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rlaksana/mcp-watchtower'

If you have feedback or need assistance with the MCP directory API, please join our Discord server