use prometheus::{
CounterVec, Encoder, GaugeVec, HistogramVec, TextEncoder, register_counter_vec,
register_gauge_vec, register_histogram_vec,
};
use std::sync::LazyLock;
use std::time::Duration;
pub static REQUEST_COUNTER: LazyLock<CounterVec> = LazyLock::new(|| {
register_counter_vec!(
"embellama_requests_total",
"Total number of requests by status",
&["status", "model"]
)
.expect("Failed to register request counter")
});
pub static REQUEST_DURATION: LazyLock<HistogramVec> = LazyLock::new(|| {
register_histogram_vec!(
"embellama_request_duration_seconds",
"Request processing time in seconds",
&["model", "status"],
vec![
0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0
]
)
.expect("Failed to register request duration histogram")
});
pub static INFERENCE_DURATION: LazyLock<HistogramVec> = LazyLock::new(|| {
register_histogram_vec!(
"embellama_inference_duration_seconds",
"Model inference time in seconds",
&["model", "batch_size"],
vec![
0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0
]
)
.expect("Failed to register inference duration histogram")
});
pub static QUEUE_DEPTH: LazyLock<GaugeVec> = LazyLock::new(|| {
register_gauge_vec!(
"embellama_queue_depth",
"Current depth of request queues",
&["worker_id"]
)
.expect("Failed to register queue depth gauge")
});
pub static ACTIVE_REQUESTS: LazyLock<GaugeVec> = LazyLock::new(|| {
register_gauge_vec!(
"embellama_active_requests",
"Number of currently active requests",
&["model"]
)
.expect("Failed to register active requests gauge")
});
pub static WORKER_UTILIZATION: LazyLock<GaugeVec> = LazyLock::new(|| {
register_gauge_vec!(
"embellama_worker_utilization",
"Worker thread utilization (0-1)",
&["worker_id"]
)
.expect("Failed to register worker utilization gauge")
});
pub static RATE_LIMITED_REQUESTS: LazyLock<CounterVec> = LazyLock::new(|| {
register_counter_vec!(
"embellama_rate_limited_requests_total",
"Total number of rate-limited requests",
&["client", "reason"]
)
.expect("Failed to register rate limited requests counter")
});
pub static ERROR_COUNTER: LazyLock<CounterVec> = LazyLock::new(|| {
register_counter_vec!(
"embellama_errors_total",
"Total number of errors by type",
&["error_type", "model"]
)
.expect("Failed to register error counter")
});
pub fn record_request_success(model: &str, duration: Duration) {
REQUEST_COUNTER.with_label_values(&["success", model]).inc();
REQUEST_DURATION
.with_label_values(&[model, "success"])
.observe(duration.as_secs_f64());
}
pub fn record_request_failure(model: &str, duration: Duration, error_type: &str) {
REQUEST_COUNTER.with_label_values(&["failure", model]).inc();
REQUEST_DURATION
.with_label_values(&[model, "failure"])
.observe(duration.as_secs_f64());
ERROR_COUNTER.with_label_values(&[error_type, model]).inc();
}
pub fn record_inference_time(model: &str, batch_size: usize, duration: Duration) {
INFERENCE_DURATION
.with_label_values(&[model, &batch_size.to_string()])
.observe(duration.as_secs_f64());
}
pub fn update_queue_depth(worker_id: usize, depth: usize) {
#[allow(clippy::cast_precision_loss)]
let depth_f64 = depth as f64;
QUEUE_DEPTH
.with_label_values(&[&worker_id.to_string()])
.set(depth_f64);
}
pub fn increment_active_requests(model: &str) {
ACTIVE_REQUESTS.with_label_values(&[model]).inc();
}
pub fn decrement_active_requests(model: &str) {
ACTIVE_REQUESTS.with_label_values(&[model]).dec();
}
pub fn update_worker_utilization(worker_id: usize, utilization: f64) {
WORKER_UTILIZATION
.with_label_values(&[&worker_id.to_string()])
.set(utilization.clamp(0.0, 1.0));
}
pub fn record_rate_limited(client: &str, reason: &str) {
RATE_LIMITED_REQUESTS
.with_label_values(&[client, reason])
.inc();
}
pub fn export_metrics() -> String {
let encoder = TextEncoder::new();
let metric_families = prometheus::gather();
let mut buffer = Vec::new();
encoder.encode(&metric_families, &mut buffer).unwrap();
String::from_utf8(buffer).unwrap()
}
pub fn init_metrics() {
LazyLock::force(&REQUEST_COUNTER);
LazyLock::force(&REQUEST_DURATION);
LazyLock::force(&INFERENCE_DURATION);
LazyLock::force(&QUEUE_DEPTH);
LazyLock::force(&ACTIVE_REQUESTS);
LazyLock::force(&WORKER_UTILIZATION);
LazyLock::force(&RATE_LIMITED_REQUESTS);
LazyLock::force(&ERROR_COUNTER);
tracing::info!("Prometheus metrics initialized");
}