use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use tokio::sync::RwLock;
static HTTP_METRICS: Lazy<HttpMetricsData> = Lazy::new(HttpMetricsData::default);
#[derive(Debug, Default)]
pub struct HttpMetricsData {
pub method_count: RwLock<HashMap<String, u64>>,
pub status_code_distribution: RwLock<HashMap<u16, u64>>,
pub interval_counter: AtomicU64,
pub request_duration: RwLock<HashMap<(String, u16), (u64, u64)>>, }
impl HttpMetricsData {
pub async fn increment_counter(&self) {
self.interval_counter.fetch_add(1, Ordering::Relaxed);
}
pub async fn update_method_count(&self, method: &str) {
let mut methods = self.method_count.write().await;
let counter = methods.entry(method.to_string()).or_insert(0);
*counter += 1;
}
pub async fn update_status_code(&self, status_code: u16) {
let mut status_codes = self.status_code_distribution.write().await;
let counter = status_codes.entry(status_code).or_insert(0);
*counter += 1;
}
pub async fn update_request_duration(&self, method: &str, status_code: u16, duration: u64) {
let mut durations = self.request_duration.write().await;
let entry = durations
.entry((method.to_string(), status_code))
.or_insert((0, 0));
entry.0 += duration;
entry.1 += 1;
}
pub async fn flush(
&self,
) -> (
HashMap<String, u64>,
HashMap<u16, u64>,
u64,
HashMap<(String, u16), u64>,
) {
let mut methods = self.method_count.write().await;
let mut status_codes = self.status_code_distribution.write().await;
let mut durations = self.request_duration.write().await;
let method_count_snapshot = methods.clone();
let status_codes_snapshot = status_codes.clone();
let rpi = self.interval_counter.swap(0, Ordering::Relaxed);
let average_durations: HashMap<(String, u16), u64> = durations
.iter()
.map(|(key, &(total_duration, count))| (key.clone(), total_duration / count))
.collect();
methods.clear();
status_codes.clear();
durations.clear();
(
method_count_snapshot,
status_codes_snapshot,
rpi,
average_durations,
)
}
}
pub struct HttpMetrics;
impl HttpMetrics {
pub async fn increment_counter() {
HTTP_METRICS.increment_counter().await;
}
pub async fn update_method_count(method: &str) {
HTTP_METRICS.update_method_count(method).await;
}
pub async fn update_status_code(status_code: u16) {
HTTP_METRICS.update_status_code(status_code).await;
}
pub async fn update_request_duration(method: &str, status_code: u16, duration: u64) {
HTTP_METRICS
.update_request_duration(method, status_code, duration)
.await;
}
pub async fn flush() -> Option<(
HashMap<String, u64>,
HashMap<u16, u64>,
u64,
HashMap<(String, u16), u64>,
)> {
let result = HTTP_METRICS.flush().await;
Some(result)
}
}
#[derive(Debug, Clone)]
pub struct HttpMetricsSnapshot {
pub requests_per_interval: u64,
pub method_count: HashMap<String, u64>,
pub status_code_distribution: HashMap<u16, u64>,
pub average_request_duration: HashMap<(String, u16), u64>,
}