#![forbid(unsafe_code)]
#![warn(missing_docs, unused_imports, dead_code)]
mod errors;
mod labels;
mod metric;
mod writer;
pub use errors::{MetricsError, Result};
pub use labels::Labels;
pub use metric::{Counter, Gauge, MetricType};
pub use writer::MetricsWriter;
pub fn get_global_metrics() -> &'static tokio::sync::OnceCell<MetricsWriter> {
static GLOBAL: tokio::sync::OnceCell<MetricsWriter> = tokio::sync::OnceCell::const_new();
&GLOBAL
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_labels_formatting() {
let labels = Labels::from(vec![
("method".to_string(), "GET".to_string()),
("status".to_string(), "200".to_string()),
]);
let formatted = labels.to_string();
assert!(formatted.contains("method=\"GET\""));
assert!(formatted.contains("status=\"200\""));
}
#[tokio::test]
async fn test_metrics_writer_creation() {
let writer = MetricsWriter::new();
assert!(writer.is_ok());
}
#[tokio::test]
async fn test_counter_increment() -> anyhow::Result<()> {
let metrics = MetricsWriter::new()?;
metrics.counter("test_counter", Vec::<(String, String)>::new(), 5.0)?;
metrics.counter("test_counter", Vec::<(String, String)>::new(), 3.0)?;
Ok(())
}
#[tokio::test]
async fn test_gauge_set() -> anyhow::Result<()> {
let metrics = MetricsWriter::new()?;
metrics.gauge("test_gauge", Vec::<(String, String)>::new(), 42.5)?;
Ok(())
}
#[test]
fn test_labels_sorting() {
let labels = Labels::from(vec![
("z_label".to_string(), "last".to_string()),
("a_label".to_string(), "first".to_string()),
]);
let formatted = labels.to_string();
let a_pos = formatted.find("a_label").unwrap();
let z_pos = formatted.find("z_label").unwrap();
assert!(a_pos < z_pos, "Labels should be sorted");
}
}