From 980fc3af6d600afd2a779f0748b60faab27ebd08 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 11 Mar 2026 12:33:19 +0000 Subject: [PATCH] feat: add metrics export as CSV/JSON (MON-04) Co-Authored-By: Claude Opus 4.6 --- core/archipelago/src/api/rpc/mod.rs | 1 + core/archipelago/src/api/rpc/monitoring.rs | 74 ++++++++++++++++++++++ loop/plan.md | 2 +- neode-ui/src/views/Monitoring.vue | 42 +++++++++++- 4 files changed, 116 insertions(+), 3 deletions(-) diff --git a/core/archipelago/src/api/rpc/mod.rs b/core/archipelago/src/api/rpc/mod.rs index e23d1e1f..a5bc1bc0 100644 --- a/core/archipelago/src/api/rpc/mod.rs +++ b/core/archipelago/src/api/rpc/mod.rs @@ -440,6 +440,7 @@ impl RpcHandler { "monitoring.alert-rules" => self.handle_monitoring_alert_rules().await, "monitoring.configure-alert" => self.handle_monitoring_configure_alert(params).await, "monitoring.acknowledge-alert" => self.handle_monitoring_acknowledge_alert(params).await, + "monitoring.export" => self.handle_monitoring_export(params).await, // System updates "update.check" => self.handle_update_check().await, diff --git a/core/archipelago/src/api/rpc/monitoring.rs b/core/archipelago/src/api/rpc/monitoring.rs index 08bdb110..4aedb5eb 100644 --- a/core/archipelago/src/api/rpc/monitoring.rs +++ b/core/archipelago/src/api/rpc/monitoring.rs @@ -116,6 +116,80 @@ impl RpcHandler { Ok(serde_json::json!({ "updated": true, "kind": kind_str })) } + /// monitoring.export — export metrics as CSV or JSON + pub(super) async fn handle_monitoring_export( + &self, + params: Option, + ) -> Result { + debug!("Exporting metrics"); + + let format = params + .as_ref() + .and_then(|p| p.get("format")) + .and_then(|v| v.as_str()) + .unwrap_or("csv"); + + let resolution = params + .as_ref() + .and_then(|p| p.get("resolution")) + .and_then(|v| v.as_str()) + .unwrap_or("minute"); + + let count = params + .as_ref() + .and_then(|p| p.get("count")) + .and_then(|v| v.as_u64()) + .unwrap_or(1440) as usize; + + let count = count.min(1440); + + let data = match resolution { + "quarter_hour" | "15min" => self.metrics_store.history_quarter_hours(count).await, + _ => self.metrics_store.history_minutes(count).await, + }; + + match format { + "json" => { + Ok(serde_json::json!({ + "format": "json", + "resolution": resolution, + "count": data.len(), + "data": data, + })) + } + _ => { + // CSV format + let mut csv = String::from( + "timestamp,cpu_percent,mem_used_bytes,mem_total_bytes,disk_used_bytes,disk_total_bytes,net_rx_bytes,net_tx_bytes,load_avg_1,load_avg_5,load_avg_15,rpc_latency_ms,ws_connections\n" + ); + for snapshot in &data { + csv.push_str(&format!( + "{},{:.1},{},{},{},{},{},{},{:.2},{:.2},{:.2},{:.1},{}\n", + snapshot.timestamp, + snapshot.system.cpu_percent, + snapshot.system.mem_used_bytes, + snapshot.system.mem_total_bytes, + snapshot.system.disk_used_bytes, + snapshot.system.disk_total_bytes, + snapshot.system.net_rx_bytes, + snapshot.system.net_tx_bytes, + snapshot.system.load_avg_1, + snapshot.system.load_avg_5, + snapshot.system.load_avg_15, + snapshot.rpc_latency_ms, + snapshot.ws_connections, + )); + } + Ok(serde_json::json!({ + "format": "csv", + "resolution": resolution, + "count": data.len(), + "csv": csv, + })) + } + } + } + /// monitoring.acknowledge-alert — acknowledge a fired alert pub(super) async fn handle_monitoring_acknowledge_alert( &self, diff --git a/loop/plan.md b/loop/plan.md index 0fee2bd3..ab3dd2fd 100644 --- a/loop/plan.md +++ b/loop/plan.md @@ -342,7 +342,7 @@ - [x] **MON-03** — Implemented alerting system. Added AlertRule and FiredAlert types to monitoring/mod.rs with 5 configurable rules (disk >90%, RAM >90%, container crash, RPC latency spike, SSL cert expiry <30 days). Metrics collector evaluates rules every 60s, fires alerts as Notifications via WebSocket. Added RPC endpoints: monitoring.alerts, monitoring.alert-rules, monitoring.configure-alert, monitoring.acknowledge-alert. Frontend: Monitoring.vue has alert history section with configurable thresholds, enable/disable toggles, dismiss buttons. CSS toggle/input styles in style.css. -- [ ] **MON-04** — Add historical data export. Add `monitoring.export` RPC endpoint that exports metrics as CSV or JSON for a given time range. Add "Export" button in monitoring UI. **Acceptance**: Can download last 24h of metrics as CSV. +- [x] **MON-04** — Added historical data export. `monitoring.export` RPC endpoint returns metrics as CSV (with headers) or JSON for configurable count/resolution. Frontend: Export CSV and Export JSON buttons in Monitoring.vue header. Creates downloadable blob file with date-stamped filename. #### Sprint 28: Remote Management (Week 5-8) diff --git a/neode-ui/src/views/Monitoring.vue b/neode-ui/src/views/Monitoring.vue index 768473b7..3a17c9c9 100644 --- a/neode-ui/src/views/Monitoring.vue +++ b/neode-ui/src/views/Monitoring.vue @@ -1,8 +1,20 @@