eshanized_polaris_core/
observability.rs1use std::sync::Arc;
4
5#[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 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 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 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 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 #[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
122pub 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}