crawlforge-mcp-server
Version:
CrawlForge MCP Server - Professional Model Context Protocol server with 19 comprehensive web scraping, crawling, and content processing tools.
174 lines (146 loc) • 4.51 kB
JavaScript
/**
* Memory Monitoring and Leak Detection Utility
* Tracks memory usage patterns and detects potential leaks
*/
export class MemoryMonitor {
constructor(options = {}) {
this.options = {
sampleInterval: options.sampleInterval || 30000, // 30 seconds
maxSamples: options.maxSamples || 100,
leakThreshold: options.leakThreshold || 50 * 1024 * 1024, // 50MB
enableLogging: options.enableLogging !== false,
alertCallback: options.alertCallback || null,
...options
};
this.samples = [];
this.isMonitoring = false;
this.intervalId = null;
this.leakWarnings = 0;
}
/**
* Start memory monitoring
*/
start() {
if (this.isMonitoring) {
return;
}
this.isMonitoring = true;
this.log('Starting memory monitoring...');
this.intervalId = setInterval(() => {
this.takeSample();
this.analyzeMemoryTrend();
}, this.options.sampleInterval);
// Take initial sample
this.takeSample();
}
/**
* Stop memory monitoring
*/
stop() {
if (!this.isMonitoring) {
return;
}
this.isMonitoring = false;
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
this.log('Memory monitoring stopped');
}
/**
* Take a memory usage sample
*/
takeSample() {
const usage = process.memoryUsage();
const timestamp = Date.now();
const sample = {
timestamp,
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
external: usage.external,
rss: usage.rss,
heapUsedMB: Math.round(usage.heapUsed / 1024 / 1024 * 100) / 100,
heapTotalMB: Math.round(usage.heapTotal / 1024 / 1024 * 100) / 100
};
this.samples.push(sample);
// Keep only the last N samples
if (this.samples.length > this.options.maxSamples) {
this.samples.shift();
}
return sample;
}
/**
* Get current memory statistics
*/
getStats() {
if (this.samples.length === 0) {
return null;
}
const latest = this.samples[this.samples.length - 1];
const peak = Math.max(...this.samples.map(s => s.heapUsed));
const average = this.samples.reduce((sum, s) => sum + s.heapUsed, 0) / this.samples.length;
return {
current: {
heapUsedMB: latest.heapUsedMB,
heapTotalMB: latest.heapTotalMB,
timestamp: latest.timestamp
},
peak: {
heapUsedMB: Math.round(peak / 1024 / 1024 * 100) / 100
},
average: {
heapUsedMB: Math.round(average / 1024 / 1024 * 100) / 100
},
samples: this.samples.length,
leakWarnings: this.leakWarnings,
isMonitoring: this.isMonitoring
};
}
/**
* Analyze memory trend for potential leaks
*/
analyzeMemoryTrend() {
if (this.samples.length < 5) {
return; // Need at least 5 samples for trend analysis
}
// Check if memory is consistently increasing
const recentSamples = this.samples.slice(-10); // Last 10 samples
let increasingCount = 0;
for (let i = 1; i < recentSamples.length; i++) {
if (recentSamples[i].heapUsed > recentSamples[i - 1].heapUsed) {
increasingCount++;
}
}
// If memory increased in 80% of recent samples, potential leak
if (increasingCount > recentSamples.length * 0.8) {
const memoryGrowth = recentSamples[recentSamples.length - 1].heapUsed - recentSamples[0].heapUsed;
if (memoryGrowth > this.options.leakThreshold) {
this.leakWarnings++;
const growthMB = Math.round(memoryGrowth / 1024 / 1024 * 100) / 100;
this.log(`Warning: Potential memory leak detected. Memory grew by ${growthMB}MB over ${recentSamples.length} samples`);
if (this.options.alertCallback) {
this.options.alertCallback({
type: 'memory_leak',
growthMB,
samples: recentSamples.length,
warnings: this.leakWarnings
});
}
}
}
}
/**
* Log messages if logging is enabled
*/
log(message) {
if (this.options.enableLogging) {
console.error(`[MemoryMonitor] ${message}`);
}
}
}
// Export singleton instance for global use
export const memoryMonitor = new MemoryMonitor({
enableLogging: process.env.NODE_ENV === 'development',
sampleInterval: 30000, // 30 seconds
leakThreshold: 100 * 1024 * 1024 // 100MB
});