cdk_prometheus/
process.rs

1use std::sync::Arc;
2
3#[cfg(feature = "system-metrics")]
4use prometheus::{Gauge, IntGauge, Registry};
5#[cfg(feature = "system-metrics")]
6use sysinfo::{Pid, System};
7
8/// System metrics collector that provides CPU, memory, disk, network, and process metrics
9#[cfg(feature = "system-metrics")]
10#[derive(Clone, Debug)]
11pub struct SystemMetrics {
12    registry: Arc<Registry>,
13    system: Arc<std::sync::Mutex<System>>,
14
15    // Process metrics (for the CDK process)
16    process_cpu_usage_percent: Gauge,
17    process_memory_bytes: IntGauge,
18    process_memory_percent: Gauge,
19}
20
21#[cfg(feature = "system-metrics")]
22impl SystemMetrics {
23    /// Create a new `SystemMetrics` instance
24    ///
25    /// # Errors
26    /// Returns an error if any of the metrics cannot be created or registered
27    pub fn new() -> crate::Result<Self> {
28        let registry = Arc::new(Registry::new());
29        // Process metrics
30        let process_cpu_usage_percent = Gauge::new(
31            "process_cpu_usage_percent",
32            "CPU usage percentage of the CDK process (0-100)",
33        )?;
34        registry.register(Box::new(process_cpu_usage_percent.clone()))?;
35
36        let process_memory_bytes = IntGauge::new(
37            "process_memory_bytes",
38            "Memory usage of the CDK process in bytes",
39        )?;
40        registry.register(Box::new(process_memory_bytes.clone()))?;
41
42        let process_memory_percent = Gauge::new(
43            "process_memory_percent",
44            "Memory usage percentage of the CDK process (0-100)",
45        )?;
46        registry.register(Box::new(process_memory_percent.clone()))?;
47
48        // Initialize system with all needed refresh kinds
49        let system = Arc::new(std::sync::Mutex::new(System::new()));
50
51        let result = Self {
52            registry,
53            system,
54            process_cpu_usage_percent,
55            process_memory_bytes,
56            process_memory_percent,
57        };
58
59        Ok(result)
60    }
61
62    /// Get the metrics registry
63    #[must_use]
64    pub fn registry(&self) -> Arc<Registry> {
65        Arc::<Registry>::clone(&self.registry)
66    }
67
68    /// Update all system metrics
69    ///
70    /// # Errors
71    /// Returns an error if the system mutex cannot be locked
72    pub fn update_metrics(&self) -> crate::Result<()> {
73        let mut system = self.system.lock().map_err(|e| {
74            crate::error::PrometheusError::SystemMetrics(format!("Failed to lock system: {e}"))
75        })?;
76        // Refresh system information
77        system.refresh_all();
78
79        // Update memory metrics
80        let total_memory = i64::try_from(system.total_memory()).unwrap_or(i64::MAX);
81
82        // Update process metrics for the current process
83        // This is a simplified approach that may not work perfectly in all cases
84        if let Some(process) = system.process(Pid::from(std::process::id() as usize)) {
85            // Get CPU usage if available
86            let process_cpu = process.cpu_usage();
87            self.process_cpu_usage_percent.set(f64::from(process_cpu));
88
89            // Get memory usage if available
90            let process_memory = i64::try_from(process.memory()).unwrap_or(i64::MAX);
91            self.process_memory_bytes.set(process_memory);
92
93            // Calculate memory percentage
94            if total_memory > 0 {
95                // Precision loss is acceptable for percentage calculation
96                #[allow(clippy::cast_precision_loss)]
97                let process_memory_percent = (process_memory as f64 / total_memory as f64) * 100.0;
98                self.process_memory_percent.set(process_memory_percent);
99            }
100        }
101
102        // Drop the system lock early to avoid resource contention
103        drop(system);
104
105        Ok(())
106    }
107}