feat: add real-time metrics collection with ring buffer storage (MON-01)
Implements monitoring/collector.rs that collects per-container CPU/RAM/network/disk, system-wide metrics, RPC latency, and WebSocket connection count every 60 seconds. Data stored in dual ring buffers: 1-min resolution (24h) and 15-min resolution (7d). Three new RPC endpoints: monitoring.current, monitoring.history, monitoring.containers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,19 +4,27 @@
|
||||
use anyhow::Result;
|
||||
use std::net::SocketAddr;
|
||||
use tracing::info;
|
||||
use tokio::signal;
|
||||
|
||||
mod api;
|
||||
mod auth;
|
||||
mod backup;
|
||||
mod config;
|
||||
mod content_server;
|
||||
mod crash_recovery;
|
||||
mod credentials;
|
||||
mod disk_monitor;
|
||||
mod health_monitor;
|
||||
mod electrs_status;
|
||||
mod container;
|
||||
mod port_allocator;
|
||||
mod data_model;
|
||||
mod federation;
|
||||
mod identity;
|
||||
mod identity_manager;
|
||||
mod marketplace;
|
||||
mod mesh;
|
||||
mod monitoring;
|
||||
mod node_message;
|
||||
mod nostr_discovery;
|
||||
mod peers;
|
||||
@@ -29,6 +37,7 @@ mod names;
|
||||
mod network;
|
||||
mod nostr_relays;
|
||||
mod update;
|
||||
mod vpn;
|
||||
|
||||
use auth::AuthManager;
|
||||
use config::Config;
|
||||
@@ -39,6 +48,8 @@ const DEV_DEFAULT_PASSWORD: &str = "password123";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let startup_start = std::time::Instant::now();
|
||||
|
||||
// Initialize tracing
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
@@ -47,12 +58,25 @@ async fn main() -> Result<()> {
|
||||
)
|
||||
.init();
|
||||
|
||||
info!("🚀 Starting Archipelago Bitcoin Node OS");
|
||||
info!("Starting Archipelago Bitcoin Node OS");
|
||||
|
||||
// Load configuration
|
||||
let config = Config::load().await?;
|
||||
info!("📁 Data directory: {}", config.data_dir.display());
|
||||
|
||||
// Crash recovery: check if previous instance shut down cleanly
|
||||
if let Some(containers) = crash_recovery::check_for_crash(&config.data_dir).await? {
|
||||
info!("🔧 Recovering {} containers from previous crash...", containers.len());
|
||||
let report = crash_recovery::recover_containers(&containers).await;
|
||||
info!(
|
||||
"🔧 Recovery complete: {}/{} containers restarted (failed: {:?})",
|
||||
report.recovered, report.total, report.failed
|
||||
);
|
||||
}
|
||||
|
||||
// Write PID marker so we can detect crashes on next startup
|
||||
crash_recovery::write_pid_marker(&config.data_dir).await?;
|
||||
|
||||
// In dev mode, ensure a default user exists so login works without manual setup
|
||||
if config.dev_mode {
|
||||
let auth = AuthManager::new(config.data_dir.clone());
|
||||
@@ -70,11 +94,42 @@ async fn main() -> Result<()> {
|
||||
.parse()
|
||||
.expect("Invalid bind address");
|
||||
|
||||
info!("🌐 Server listening on http://{}", addr);
|
||||
info!("📡 RPC API: http://{}/rpc/v1", addr);
|
||||
info!("🔌 WebSocket: ws://{}/ws", addr);
|
||||
// Spawn background update scheduler
|
||||
let update_data_dir = config.data_dir.clone();
|
||||
tokio::spawn(async move {
|
||||
update::run_update_scheduler(update_data_dir).await;
|
||||
});
|
||||
|
||||
server.serve(addr).await?;
|
||||
// Spawn periodic container snapshot (for crash recovery)
|
||||
crash_recovery::spawn_snapshot_task(config.data_dir.clone());
|
||||
|
||||
// Spawn disk space monitor (warns at 85%, auto-cleans at 90%)
|
||||
disk_monitor::spawn_disk_monitor(config.data_dir.clone());
|
||||
|
||||
let startup_ms = startup_start.elapsed().as_millis();
|
||||
info!("Server listening on http://{} (startup: {}ms)", addr, startup_ms);
|
||||
info!("RPC API: http://{}/rpc/v1", addr);
|
||||
info!("WebSocket: ws://{}/ws", addr);
|
||||
|
||||
// Graceful shutdown: wait for SIGTERM or SIGINT
|
||||
let shutdown = async {
|
||||
let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("Failed to register SIGTERM handler");
|
||||
tokio::select! {
|
||||
_ = signal::ctrl_c() => {
|
||||
info!("Received SIGINT (Ctrl+C), initiating graceful shutdown...");
|
||||
}
|
||||
_ = sigterm.recv() => {
|
||||
info!("Received SIGTERM, initiating graceful shutdown...");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
server.serve_with_shutdown(addr, shutdown).await?;
|
||||
|
||||
// Clean shutdown: remove PID marker so next startup doesn't trigger recovery
|
||||
crash_recovery::remove_pid_marker(&config.data_dir).await;
|
||||
|
||||
info!("Archipelago shut down cleanly");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user