1#![warn(missing_docs)]
52#![allow(unsafe_code)] use std::sync::OnceLock;
55
56mod counter;
57mod gauge;
58mod timer;
59mod rate_meter;
60mod registry;
61mod system_health;
62mod async_support;
63mod adaptive;
64
65pub use counter::*;
66pub use gauge::{Gauge, GaugeStats};
67pub use timer::*;
68pub use rate_meter::{RateMeter, RateStats};
69pub use registry::*;
70pub use system_health::*;
71pub use async_support::{AsyncTimerExt, AsyncTimerGuard, AsyncMetricBatch};
72pub use adaptive::{AdaptiveSampler, SamplingStrategy, MetricCircuitBreaker, BackpressureController};
73
74pub use gauge::specialized as gauge_specialized;
76pub use rate_meter::specialized as rate_meter_specialized;
77
78pub static METRICS: OnceLock<MetricsCore> = OnceLock::new();
80
81pub fn init() -> &'static MetricsCore {
85 METRICS.get_or_init(MetricsCore::new)
86}
87
88pub fn metrics() -> &'static MetricsCore {
92 METRICS.get().expect("Metrics not initialized - call metrics_lib::init() first")
93}
94
95#[repr(align(64))] pub struct MetricsCore {
98 registry: Registry,
99 system: SystemHealth,
100}
101
102impl MetricsCore {
103 pub fn new() -> Self {
105 Self {
106 registry: Registry::new(),
107 system: SystemHealth::new(),
108 }
109 }
110
111 #[inline(always)]
113 pub fn counter(&self, name: &'static str) -> std::sync::Arc<Counter> {
114 self.registry.get_or_create_counter(name)
115 }
116
117 #[inline(always)]
119 pub fn gauge(&self, name: &'static str) -> std::sync::Arc<Gauge> {
120 self.registry.get_or_create_gauge(name)
121 }
122
123 #[inline(always)]
125 pub fn timer(&self, name: &'static str) -> std::sync::Arc<Timer> {
126 self.registry.get_or_create_timer(name)
127 }
128
129 #[inline(always)]
131 pub fn rate(&self, name: &'static str) -> std::sync::Arc<RateMeter> {
132 self.registry.get_or_create_rate_meter(name)
133 }
134
135 #[inline]
137 pub fn time<T>(&self, name: &'static str, f: impl FnOnce() -> T) -> T {
138 let binding = self.timer(name);
139 let timer = binding.start();
140 let result = f();
141 timer.stop();
142 result
143 }
144
145 #[inline(always)]
147 pub fn system(&self) -> &SystemHealth {
148 &self.system
149 }
150
151 #[inline(always)]
153 pub fn registry(&self) -> &Registry {
154 &self.registry
155 }
156}
157
158impl Default for MetricsCore {
159 fn default() -> Self {
160 Self::new()
161 }
162}
163
164pub type Result<T> = std::result::Result<T, MetricsError>;
166
167#[derive(Debug, Clone, PartialEq)]
169pub enum MetricsError {
170 CircuitOpen,
172 Overloaded,
174 InvalidName,
176 Config(String),
178}
179
180impl std::fmt::Display for MetricsError {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 match self {
183 MetricsError::CircuitOpen => write!(f, "Circuit breaker is open"),
184 MetricsError::Overloaded => write!(f, "System is overloaded"),
185 MetricsError::InvalidName => write!(f, "Invalid metric name"),
186 MetricsError::Config(msg) => write!(f, "Configuration error: {msg}"),
187 }
188 }
189}
190
191impl std::error::Error for MetricsError {}
192
193pub mod prelude {
195 pub use crate::{init, metrics, METRICS, MetricsCore, MetricsError, Result};
196 pub use crate::{Counter, Gauge, Timer, RateMeter, SystemHealth, Registry};
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_metrics_initialization() {
205 let metrics = MetricsCore::new();
206
207 metrics.counter("test").inc();
209 assert_eq!(metrics.counter("test").get(), 1);
210
211 metrics.gauge("test").set(42.5);
212 assert_eq!(metrics.gauge("test").get(), 42.5);
213
214 let _cpu = metrics.system().cpu_used();
216 let _mem = metrics.system().mem_used_mb();
217 }
218
219 #[test]
220 fn test_global_metrics() {
221 let _metrics = init();
222
223 metrics().counter("global_test").inc();
225 assert_eq!(metrics().counter("global_test").get(), 1);
226 }
227}