Files
furumi-ng/furumi-server/src/metrics.rs
T

129 lines
3.4 KiB
Rust
Raw Normal View History

use once_cell::sync::Lazy;
use prometheus::{
register_counter, register_counter_vec, register_gauge, register_histogram_vec,
Counter, CounterVec, Encoder, Gauge, HistogramVec, TextEncoder,
};
use std::time::Instant;
// --- Counters ---
pub static GRPC_REQUESTS_TOTAL: Lazy<CounterVec> = Lazy::new(|| {
register_counter_vec!(
"furumi_grpc_requests_total",
"Total number of gRPC requests",
&["method", "status"]
)
.unwrap()
});
pub static BYTES_READ_TOTAL: Lazy<Counter> = Lazy::new(|| {
register_counter!(
"furumi_bytes_read_total",
"Total number of bytes read from disk and streamed to clients"
)
.unwrap()
});
pub static FILE_OPEN_ERRORS_TOTAL: Lazy<Counter> = Lazy::new(|| {
register_counter!(
"furumi_file_open_errors_total",
"Total number of file open errors (not found, permission denied, etc.)"
)
.unwrap()
});
pub static AUTH_FAILURES_TOTAL: Lazy<Counter> = Lazy::new(|| {
register_counter!(
"furumi_auth_failures_total",
"Total number of authentication failures"
)
.unwrap()
});
// --- Histogram ---
pub static GRPC_REQUEST_DURATION: Lazy<HistogramVec> = Lazy::new(|| {
register_histogram_vec!(
"furumi_grpc_request_duration_seconds",
"Duration of gRPC requests in seconds",
&["method"],
vec![0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0]
)
.unwrap()
});
// --- Gauges ---
pub static ACTIVE_STREAMS: Lazy<Gauge> = Lazy::new(|| {
register_gauge!(
"furumi_active_streams",
"Number of currently active streaming connections (ReadFile/ReadDir)"
)
.unwrap()
});
/// Helper to track and record a gRPC call's duration and status.
pub struct RequestTimer {
method: &'static str,
start: Instant,
}
impl RequestTimer {
pub fn new(method: &'static str) -> Self {
GRPC_REQUESTS_TOTAL
.with_label_values(&[method, "started"])
.inc();
Self {
method,
start: Instant::now(),
}
}
pub fn finish_ok(self) {
let elapsed = self.start.elapsed().as_secs_f64();
GRPC_REQUEST_DURATION
.with_label_values(&[self.method])
.observe(elapsed);
GRPC_REQUESTS_TOTAL
.with_label_values(&[self.method, "ok"])
.inc();
}
pub fn finish_err(self) {
let elapsed = self.start.elapsed().as_secs_f64();
GRPC_REQUEST_DURATION
.with_label_values(&[self.method])
.observe(elapsed);
GRPC_REQUESTS_TOTAL
.with_label_values(&[self.method, "error"])
.inc();
}
}
2026-03-11 01:39:29 +00:00
/// An RAII guard that increments the ACTIVE_STREAMS gauge when created
/// and decrements it when dropped. This ensures streams are correctly counted
/// even if they terminate abruptly.
pub struct ActiveStreamGuard;
impl ActiveStreamGuard {
pub fn new() -> Self {
ACTIVE_STREAMS.inc();
Self
}
}
impl Drop for ActiveStreamGuard {
fn drop(&mut self) {
ACTIVE_STREAMS.dec();
}
}
/// Render all registered metrics in Prometheus text format.
pub fn render_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()
}