use prometheus_client::registry::Registry;
use std::sync::{Arc, OnceLock};
use parking_lot::RwLock;
pub static METRICS_REGISTRY: OnceLock<Arc<MetricsRegistry>> = OnceLock::new();
pub struct MetricsRegistry {
registry: Arc<RwLock<Registry>>,
}
impl MetricsRegistry {
pub fn new() -> Self {
Self {
registry: Arc::new(RwLock::new(Registry::default())),
}
}
pub fn global() -> Arc<MetricsRegistry> {
METRICS_REGISTRY
.get_or_init(|| Arc::new(MetricsRegistry::new()))
.clone()
}
pub fn registry(&self) -> Arc<RwLock<Registry>> {
self.registry.clone()
}
pub fn encode(&self) -> Result<String, crate::metrics::MetricsError> {
let registry = self.registry.read();
let mut buffer = String::new();
prometheus_client::encoding::text::encode(&mut buffer, ®istry)
.map_err(|e| crate::metrics::MetricsError::EncodingError(e.to_string()))?;
Ok(buffer)
}
}
impl Default for MetricsRegistry {
fn default() -> Self {
Self::new()
}
}
impl Clone for MetricsRegistry {
fn clone(&self) -> Self {
Self {
registry: self.registry.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry_creation() {
let registry = MetricsRegistry::new();
assert!(registry.encode().is_ok());
}
#[test]
fn test_global_registry() {
let registry1 = MetricsRegistry::global();
let registry2 = MetricsRegistry::global();
assert!(Arc::ptr_eq(®istry1, ®istry2));
}
#[test]
fn test_registry_clone() {
let registry1 = MetricsRegistry::new();
let registry2 = registry1.clone();
assert!(Arc::ptr_eq(®istry1.registry(), ®istry2.registry()));
}
}