confium_coordinator/coordinator/
metrics.rs1use std::sync::atomic::{AtomicU64, Ordering};
8
9#[derive(Debug, Default)]
12pub struct CoordinatorMetrics {
13 sessions_created: AtomicU64,
15 sessions_completed: AtomicU64,
17 sessions_expired: AtomicU64,
19 sessions_aborted: AtomicU64,
21 aggregations_attempted: AtomicU64,
23 aggregations_failed: AtomicU64,
25 active_sessions: AtomicU64,
27 registered_signers: AtomicU64,
29 bytes_processed: AtomicU64,
31}
32
33impl CoordinatorMetrics {
34 pub fn record_session_created(&self) {
36 self.sessions_created.fetch_add(1, Ordering::Relaxed);
37 self.active_sessions.fetch_add(1, Ordering::Relaxed);
38 }
39
40 pub fn record_session_completed(&self) {
42 self.sessions_completed.fetch_add(1, Ordering::Relaxed);
43 self.active_sessions.fetch_sub(1, Ordering::Relaxed);
44 }
45
46 pub fn record_session_expired(&self) {
48 self.sessions_expired.fetch_add(1, Ordering::Relaxed);
49 self.active_sessions.fetch_sub(1, Ordering::Relaxed);
50 }
51
52 pub fn record_session_aborted(&self) {
54 self.sessions_aborted.fetch_add(1, Ordering::Relaxed);
55 self.active_sessions.fetch_sub(1, Ordering::Relaxed);
56 }
57
58 pub fn record_aggregation_attempted(&self) {
60 self.aggregations_attempted.fetch_add(1, Ordering::Relaxed);
61 }
62
63 pub fn record_aggregation_failed(&self) {
65 self.aggregations_failed.fetch_add(1, Ordering::Relaxed);
66 }
67
68 pub fn set_registered_signers(&self, count: u64) {
70 self.registered_signers.store(count, Ordering::Relaxed);
71 }
72
73 pub fn record_bytes(&self, bytes: u64) {
75 self.bytes_processed.fetch_add(bytes, Ordering::Relaxed);
76 }
77
78 pub fn render_prometheus(&self) -> String {
80 let mut out = String::new();
81 out.push_str("# HELP confium_sessions_created_total Total sessions created.\n");
82 out.push_str("# TYPE confium_sessions_created_total counter\n");
83 out.push_str(&format!(
84 "confium_sessions_created_total {}\n",
85 self.sessions_created.load(Ordering::Relaxed)
86 ));
87
88 out.push_str("# HELP confium_sessions_completed_total Total sessions completed.\n");
89 out.push_str("# TYPE confium_sessions_completed_total counter\n");
90 out.push_str(&format!(
91 "confium_sessions_completed_total {}\n",
92 self.sessions_completed.load(Ordering::Relaxed)
93 ));
94
95 out.push_str("# HELP confium_sessions_expired_total Total sessions expired.\n");
96 out.push_str("# TYPE confium_sessions_expired_total counter\n");
97 out.push_str(&format!(
98 "confium_sessions_expired_total {}\n",
99 self.sessions_expired.load(Ordering::Relaxed)
100 ));
101
102 out.push_str("# HELP confium_sessions_aborted_total Total sessions aborted.\n");
103 out.push_str("# TYPE confium_sessions_aborted_total counter\n");
104 out.push_str(&format!(
105 "confium_sessions_aborted_total {}\n",
106 self.sessions_aborted.load(Ordering::Relaxed)
107 ));
108
109 out.push_str("# HELP confium_aggregations_attempted_total Total aggregation attempts.\n");
110 out.push_str("# TYPE confium_aggregations_attempted_total counter\n");
111 out.push_str(&format!(
112 "confium_aggregations_attempted_total {}\n",
113 self.aggregations_attempted.load(Ordering::Relaxed)
114 ));
115
116 out.push_str("# HELP confium_aggregations_failed_total Total failed aggregations.\n");
117 out.push_str("# TYPE confium_aggregations_failed_total counter\n");
118 out.push_str(&format!(
119 "confium_aggregations_failed_total {}\n",
120 self.aggregations_failed.load(Ordering::Relaxed)
121 ));
122
123 out.push_str("# HELP confium_active_sessions Currently active sessions.\n");
124 out.push_str("# TYPE confium_active_sessions gauge\n");
125 out.push_str(&format!(
126 "confium_active_sessions {}\n",
127 self.active_sessions.load(Ordering::Relaxed)
128 ));
129
130 out.push_str("# HELP confium_registered_signers Currently registered signers.\n");
131 out.push_str("# TYPE confium_registered_signers gauge\n");
132 out.push_str(&format!(
133 "confium_registered_signers {}\n",
134 self.registered_signers.load(Ordering::Relaxed)
135 ));
136
137 out.push_str("# HELP confium_bytes_processed_total Total bytes processed.\n");
138 out.push_str("# TYPE confium_bytes_processed_total counter\n");
139 out.push_str(&format!(
140 "confium_bytes_processed_total {}\n",
141 self.bytes_processed.load(Ordering::Relaxed)
142 ));
143
144 out
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn empty_metrics_render_correctly() {
154 let m = CoordinatorMetrics::default();
155 let text = m.render_prometheus();
156 assert!(text.contains("confium_sessions_created_total 0"));
157 assert!(text.contains("confium_active_sessions 0"));
158 }
159
160 #[test]
161 fn session_lifecycle_increments() {
162 let m = CoordinatorMetrics::default();
163 m.record_session_created();
164 m.record_session_created();
165 m.record_session_completed();
166 m.record_session_expired();
167
168 let text = m.render_prometheus();
169 assert!(text.contains("confium_sessions_created_total 2"));
170 assert!(text.contains("confium_sessions_completed_total 1"));
171 assert!(text.contains("confium_sessions_expired_total 1"));
172 assert!(text.contains("confium_active_sessions 0"));
173 }
174
175 #[test]
176 fn aggregation_metrics() {
177 let m = CoordinatorMetrics::default();
178 m.record_aggregation_attempted();
179 m.record_aggregation_attempted();
180 m.record_aggregation_failed();
181
182 let text = m.render_prometheus();
183 assert!(text.contains("confium_aggregations_attempted_total 2"));
184 assert!(text.contains("confium_aggregations_failed_total 1"));
185 }
186
187 #[test]
188 fn prometheus_format_has_help_and_type() {
189 let m = CoordinatorMetrics::default();
190 let text = m.render_prometheus();
191 assert!(text.contains("# HELP"));
192 assert!(text.contains("# TYPE"));
193 assert!(text.contains("counter"));
194 assert!(text.contains("gauge"));
195 }
196
197 #[test]
198 fn registered_signers_gauge() {
199 let m = CoordinatorMetrics::default();
200 m.set_registered_signers(5);
201 let text = m.render_prometheus();
202 assert!(text.contains("confium_registered_signers 5"));
203 }
204
205 #[test]
206 fn bytes_processed_accumulates() {
207 let m = CoordinatorMetrics::default();
208 m.record_bytes(100);
209 m.record_bytes(250);
210 let text = m.render_prometheus();
211 assert!(text.contains("confium_bytes_processed_total 350"));
212 }
213}