eshanized_polaris_core/
observability.rs

1//! Observability and metrics collection.
2
3use std::sync::Arc;
4
5/// Metrics collector for cluster operations
6#[derive(Debug, Clone)]
7pub struct MetricsCollector {
8    #[cfg(feature = "metrics")]
9    task_submitted: Arc<prometheus::IntCounter>,
10    #[cfg(feature = "metrics")]
11    task_completed: Arc<prometheus::IntCounter>,
12    #[cfg(feature = "metrics")]
13    task_failed: Arc<prometheus::IntCounter>,
14    #[cfg(feature = "metrics")]
15    task_duration: Arc<prometheus::Histogram>,
16    #[cfg(not(feature = "metrics"))]
17    _phantom: std::marker::PhantomData<()>,
18}
19
20impl MetricsCollector {
21    /// Create a new metrics collector
22    pub fn new() -> Self {
23        #[cfg(feature = "metrics")]
24        {
25            let task_submitted = Arc::new(
26                prometheus::IntCounter::new(
27                    "polaris_tasks_submitted_total",
28                    "Total number of tasks submitted",
29                )
30                .unwrap(),
31            );
32
33            let task_completed = Arc::new(
34                prometheus::IntCounter::new(
35                    "polaris_tasks_completed_total",
36                    "Total number of tasks completed",
37                )
38                .unwrap(),
39            );
40
41            let task_failed = Arc::new(
42                prometheus::IntCounter::new(
43                    "polaris_tasks_failed_total",
44                    "Total number of tasks failed",
45                )
46                .unwrap(),
47            );
48
49            let task_duration = Arc::new(
50                prometheus::Histogram::with_opts(
51                    prometheus::HistogramOpts::new(
52                        "polaris_task_duration_seconds",
53                        "Task execution duration in seconds",
54                    )
55                    .buckets(vec![0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0]),
56                )
57                .unwrap(),
58            );
59
60            Self {
61                task_submitted,
62                task_completed,
63                task_failed,
64                task_duration,
65            }
66        }
67
68        #[cfg(not(feature = "metrics"))]
69        {
70            Self {
71                _phantom: std::marker::PhantomData,
72            }
73        }
74    }
75
76    /// Record task submission
77    pub fn record_task_submitted(&self) {
78        tracing::debug!("Task submitted");
79        #[cfg(feature = "metrics")]
80        {
81            self.task_submitted.inc();
82        }
83    }
84
85    /// Record task completion
86    pub fn record_task_completed(&self, duration_ms: u64) {
87        tracing::debug!(duration_ms = %duration_ms, "Task completed");
88        #[cfg(feature = "metrics")]
89        {
90            self.task_completed.inc();
91            self.task_duration.observe(duration_ms as f64 / 1000.0);
92        }
93    }
94
95    /// Record task failure
96    pub fn record_task_failed(&self) {
97        tracing::warn!("Task failed");
98        #[cfg(feature = "metrics")]
99        {
100            self.task_failed.inc();
101        }
102    }
103
104    /// Get Prometheus registry (if metrics enabled)
105    #[cfg(feature = "metrics")]
106    pub fn register_with(&self, registry: &prometheus::Registry) -> Result<(), prometheus::Error> {
107        registry.register(Box::new(self.task_submitted.as_ref().clone()))?;
108        registry.register(Box::new(self.task_completed.as_ref().clone()))?;
109        registry.register(Box::new(self.task_failed.as_ref().clone()))?;
110        registry.register(Box::new(self.task_duration.as_ref().clone()))?;
111        Ok(())
112    }
113
114}
115
116impl Default for MetricsCollector {
117    fn default() -> Self {
118        Self::new()
119    }
120}
121
122/// Initialize tracing subscriber
123pub fn init_tracing() {
124    use tracing_subscriber::{fmt, prelude::*, EnvFilter};
125
126    tracing_subscriber::registry()
127        .with(fmt::layer())
128        .with(
129            EnvFilter::try_from_default_env()
130                .unwrap_or_else(|_| EnvFilter::new("polaris=info")),
131        )
132        .init();
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_metrics_collector_creation() {
141        let collector = MetricsCollector::new();
142        collector.record_task_submitted();
143        collector.record_task_completed(100);
144        collector.record_task_failed();
145    }
146}