Skip to main content
Glama
get-14day-anomaly-analysis.cjsβ€’10.3 kB
#!/usr/bin/env node // Get 14-day anomaly analysis const { spawn } = require('child_process'); async function get14DayAnomalyAnalysis() { console.log('πŸ’° 14-DAY AWS ANOMALY COST IMPACT ANALYSIS'); console.log('=' .repeat(58)); console.log('πŸ“… Period: August 13, 2025 - August 26, 2025'); const server = spawn('node', ['dist/index.js'], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, UMBRELLA_API_BASE_URL: 'https://api-front.umbrellacost.io/api/v1' } }); const responses = []; let requestId = 1; server.stdout.on('data', (data) => { const lines = data.toString().split('\n').filter(line => line.trim()); for (const line of lines) { try { const response = JSON.parse(line); responses.push(response); } catch (e) {} } }); // Suppress stderr for cleaner output server.stderr.on('data', () => {}); await new Promise(resolve => setTimeout(resolve, 2000)); // Auth const authRequest = { jsonrpc: "2.0", id: requestId++, method: "tools/call", params: { name: 'authenticate_user', arguments: { username: 'david+saola@umbrellacost.com', password: 'Dsamsung1!' } } }; server.stdin.write(JSON.stringify(authRequest) + '\n'); await new Promise(resolve => setTimeout(resolve, 5000)); // Request 14-day anomaly analysis console.log('πŸ” Requesting 14-day anomaly data...'); const anomaliesRequest = { jsonrpc: "2.0", id: requestId++, method: "tools/call", params: { name: 'api___anomaly_detection', arguments: { startDate: "2025-08-13", endDate: "2025-08-26", isPpApplied: "false" } } }; server.stdin.write(JSON.stringify(anomaliesRequest) + '\n'); // Wait for response with extended timeout for 14 days let anomaliesResponse = null; for (let i = 0; i < 60 && !anomaliesResponse; i++) { await new Promise(resolve => setTimeout(resolve, 1000)); anomaliesResponse = responses.find(r => r.id === 2); if (i === 15) console.log('⏳ Processing 14 days of data...'); if (i === 30) console.log('⏳ Still processing...'); if (i === 45) console.log('⏳ Almost done...'); } if (anomaliesResponse && anomaliesResponse.result?.content?.[0]?.text) { const text = anomaliesResponse.result.content[0].text; console.log(`βœ… Response received (${text.length.toLocaleString()} characters)`); // Parse the JSON response const jsonMatch = text.match(/```json\n([\s\S]*?)\n```/); if (jsonMatch) { try { const data = JSON.parse(jsonMatch[1]); if (data.anomalies && Array.isArray(data.anomalies)) { const anomalies = data.anomalies; console.log('\nπŸ’° 14-DAY ANOMALY COST IMPACT ANALYSIS RESULTS'); console.log('=' .repeat(53)); if (anomalies.length === 0) { console.log('πŸ“Š No anomalies detected in the last 14 days'); console.log('βœ… This indicates stable AWS costs during this period'); console.log('\nπŸ’° COST IMPACT: $0.00'); console.log('βœ… No financial impact from anomalies'); } else { // Calculate total cost impact let totalCostImpact = 0; let totalCurrentCost = 0; let openAnomalies = 0; let closedAnomalies = 0; const serviceBreakdown = {}; const topAnomalies = []; const dailyBreakdown = {}; anomalies.forEach(anomaly => { const impact = parseFloat(anomaly.totalCostImpact || anomaly.impact || 0); const currentCost = parseFloat(anomaly.currentCost || 0); const service = anomaly.serviceName || 'Unknown Service'; const isOpen = !(anomaly.isClosed || anomaly.is_closed); const startDate = new Date((anomaly.startTime || 0) * 1000).toISOString().split('T')[0]; totalCostImpact += impact; totalCurrentCost += currentCost; if (isOpen) openAnomalies++; else closedAnomalies++; // Service breakdown if (!serviceBreakdown[service]) { serviceBreakdown[service] = { count: 0, totalImpact: 0, totalCurrentCost: 0 }; } serviceBreakdown[service].count++; serviceBreakdown[service].totalImpact += impact; serviceBreakdown[service].totalCurrentCost += currentCost; // Daily breakdown if (!dailyBreakdown[startDate]) { dailyBreakdown[startDate] = { count: 0, totalImpact: 0 }; } dailyBreakdown[startDate].count++; dailyBreakdown[startDate].totalImpact += impact; // Top anomalies by impact if (impact > 0 || currentCost > 0) { topAnomalies.push({ service, impact, currentCost, percentChange: anomaly.percentChange || 0, accountId: anomaly.accountId || anomaly.linkedAccountId, status: isOpen ? 'Open' : 'Closed', startDate, endDate: anomaly.endDate || 'Ongoing' }); } }); // Sort top anomalies by impact topAnomalies.sort((a, b) => b.impact - a.impact); // Display results console.log(`πŸ“Š SUMMARY:`); console.log(` Total Anomalies: ${anomalies.length.toLocaleString()}`); console.log(` πŸ”“ Open: ${openAnomalies.toLocaleString()}`); console.log(` πŸ”’ Closed: ${closedAnomalies.toLocaleString()}`); console.log(`\nπŸ’° FINANCIAL IMPACT:`); console.log(` Total Cost Impact: $${totalCostImpact.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`); console.log(` Total Current Cost: $${totalCurrentCost.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`); // Daily breakdown const sortedDays = Object.entries(dailyBreakdown) .sort((a, b) => b[1].totalImpact - a[1].totalImpact); if (sortedDays.length > 0) { console.log(`\nπŸ“… DAILY BREAKDOWN (Top Days):`); sortedDays.slice(0, 5).forEach(([date, data]) => { console.log(` ${date}: ${data.count} anomalies, $${data.totalImpact.toLocaleString('en-US', {minimumFractionDigits: 2})} impact`); }); } // Top services by cost impact const topServices = Object.entries(serviceBreakdown) .map(([service, data]) => ({ service, ...data })) .sort((a, b) => b.totalImpact - a.totalImpact) .slice(0, 5); if (topServices.length > 0) { console.log(`\nπŸ† TOP SERVICES BY COST IMPACT:`); topServices.forEach((item, i) => { console.log(` ${i+1}. ${item.service}`); console.log(` Impact: $${item.totalImpact.toLocaleString('en-US', {minimumFractionDigits: 2})} | Anomalies: ${item.count}`); }); } // Top individual anomalies if (topAnomalies.length > 0) { console.log(`\nπŸ”₯ TOP INDIVIDUAL ANOMALIES:`); topAnomalies.slice(0, 5).forEach((anomaly, i) => { console.log(` ${i+1}. ${anomaly.service} (${anomaly.status})`); console.log(` πŸ’° Impact: $${anomaly.impact.toLocaleString('en-US', {minimumFractionDigits: 2})}`); console.log(` πŸ“ˆ Change: ${anomaly.percentChange.toFixed(1)}%`); console.log(` 🏒 Account: ${anomaly.accountId}`); console.log(` πŸ“… Date: ${anomaly.startDate}`); }); } // Impact assessment console.log(`\nπŸ“Š IMPACT ASSESSMENT:`); if (totalCostImpact > 5000) { console.log(`🚨 HIGH IMPACT - Requires immediate attention`); } else if (totalCostImpact > 1000) { console.log(`⚑ MODERATE IMPACT - Should be monitored`); } else if (totalCostImpact > 100) { console.log(`⚠️ LOW-MODERATE IMPACT - Within acceptable range`); } else if (totalCostImpact > 0) { console.log(`βœ… MINIMAL IMPACT - Normal cost variance`); } } console.log(`\nβœ… FINAL ANSWER FOR Q14 (14-day analysis):`); if (anomalies.length > 0) { const totalImpact = anomalies.reduce((sum, a) => sum + parseFloat(a.totalCostImpact || a.impact || 0), 0); console.log(`πŸ’° Cost impact in last 14 days: $${totalImpact.toLocaleString('en-US', {minimumFractionDigits: 2})}`); console.log(`πŸ“Š Based on ${anomalies.length} anomalies across ${Object.keys(serviceBreakdown).length} AWS services`); } else { console.log(`πŸ’° Cost impact in last 14 days: $0.00`); console.log(`βœ… No anomalies = stable costs over 14-day period`); } } else { console.log('❌ No anomalies array found in response'); } } catch (e) { console.log('❌ JSON parsing error:', e.message); console.log('First 300 chars of response:'); console.log(text.substring(0, 300)); } } else { console.log('❌ No JSON block found in response'); console.log('Response preview:', text.substring(0, 200)); } } else { console.log('❌ No response received within 60 seconds'); console.log(`Total responses: ${responses.length}`); if (responses.length > 0) { console.log('Available response IDs:', responses.map(r => r.id)); } } server.kill(); } get14DayAnomalyAnalysis().catch(console.error);

Latest Blog Posts

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/daviddraiumbrella/invoice-monitoring'

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