use anyhow::Result; use clap::Parser; use tracing::{error, info}; use tracing_subscriber::EnvFilter; mod agent; mod collectors; mod communication; mod config; mod notifications; use agent::Agent; /// Get version showing cm-dashboard-agent package hash for easy deployment verification fn get_version() -> &'static str { // Get the path of the current executable let exe_path = std::env::current_exe().expect("Failed to get executable path"); let exe_str = exe_path.to_string_lossy(); // Extract Nix store hash from path like /nix/store/HASH-cm-dashboard-v0.1.8/bin/cm-dashboard-agent let hash_part = exe_str.strip_prefix("/nix/store/").expect("Not a nix store path"); let hash = hash_part.split('-').next().expect("Invalid nix store path format"); assert!(hash.len() >= 8, "Hash too short"); // Return first 8 characters of nix store hash let short_hash = hash[..8].to_string(); Box::leak(short_hash.into_boxed_str()) } #[derive(Parser)] #[command(name = "cm-dashboard-agent")] #[command(about = "CM Dashboard metrics agent with individual metric collection")] #[command(version = get_version())] struct Cli { /// Increase logging verbosity (-v, -vv) #[arg(short, long, action = clap::ArgAction::Count)] verbose: u8, /// Configuration file path (required) #[arg(short, long)] config: String, } #[tokio::main] async fn main() -> Result<()> { let cli = Cli::parse(); // Setup logging let log_level = match cli.verbose { 0 => "info", 1 => "debug", _ => "trace", }; tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env().add_directive(log_level.parse()?)) .init(); info!("CM Dashboard Agent starting with individual metrics architecture..."); // Create and run agent let mut agent = Agent::new(Some(cli.config)).await?; // Setup graceful shutdown channel let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); let ctrl_c = async { tokio::signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); }; // Run agent with graceful shutdown tokio::select! { result = agent.run(shutdown_rx) => { if let Err(e) = result { error!("Agent error: {}", e); return Err(e); } } _ = ctrl_c => { info!("Shutdown signal received, stopping agent..."); let _ = shutdown_tx.send(()); // Give agent time to shutdown gracefully tokio::time::sleep(std::time::Duration::from_millis(100)).await; } } info!("Agent shutdown complete"); Ok(()) }