129 lines
3.4 KiB
Rust
129 lines
3.4 KiB
Rust
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();
|
|
}
|
|
}
|
|
|
|
/// 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()
|
|
}
|