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