use crate::server::axum::response::ApiError;
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};
pub const DEFAULT_DURATION_BUCKETS: &[f64] = &[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0];
pub struct PrometheusHandler {}
impl PrometheusHandler {
pub fn get_handle() -> Result<PrometheusHandle, ApiError> {
Self::get_handle_with_buckets(DEFAULT_DURATION_BUCKETS)
}
pub fn get_handle_with_buckets(buckets: &[f64]) -> Result<PrometheusHandle, ApiError> {
PrometheusBuilder::new()
.set_buckets_for_metric(Matcher::Full("http_requests_duration_seconds".to_string()), buckets)
.map_err(|err| ApiError::InternalServerError(err.to_string()))?
.install_recorder()
.map_err(|err| ApiError::InternalServerError(err.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_duration_buckets_are_monotonically_increasing() {
assert!(!DEFAULT_DURATION_BUCKETS.is_empty());
for pair in DEFAULT_DURATION_BUCKETS.windows(2) {
assert!(pair[0] < pair[1], "buckets must be strictly increasing: {pair:?}");
}
}
#[test]
fn handler_install_recorder_lifecycle() {
let handle =
PrometheusHandler::get_handle_with_buckets(&[0.001, 0.01, 0.1]).expect("first install should succeed");
let _rendered = handle.render();
let err = PrometheusHandler::get_handle().expect_err("second install must fail");
assert!(matches!(err, ApiError::InternalServerError(_)));
let err = PrometheusHandler::get_handle_with_buckets(&[0.5, 1.0]).expect_err("third install must fail");
assert!(matches!(err, ApiError::InternalServerError(_)));
}
}