Files
SentinelMesh/backend/src/routes/prometheus.rs
T
gilles f0a071e83a feat(backend): historique, SSE et Prometheus — Phase 6
- Migration 002 : table metrics_history (index agent_id/timestamp)
- AppState : broadcast channels (metrics_tx, network_tx) + FromRef<SqlitePool>
- GET /api/v1/history/{agent_id}?hours=N : série temporelle, rétention 7 jours
- POST /api/v1/metrics : écrit dans history + broadcast SSE
- GET /api/v1/stream : Server-Sent Events (events metrics + network)
- GET /metrics : endpoint Prometheus text/plain (CPU, RAM, disque, temp, réseau)
- Bump version API 0.2.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 06:30:34 +02:00

63 lines
2.5 KiB
Rust

use axum::{extract::State, http::header, response::IntoResponse};
use sqlx::SqlitePool;
use crate::error::Result;
/// Exposition des métriques au format Prometheus text (scraping Grafana/Prometheus).
///
/// Endpoint : GET /metrics
/// Compatible avec prometheus.yml :
/// scrape_configs:
/// - job_name: sentinelmesh
/// static_configs:
/// - targets: ['sentinelmesh:8080']
pub async fn metrics(State(db): State<SqlitePool>) -> Result<impl IntoResponse> {
let rows = sqlx::query_as::<_, (
String, String,
Option<f64>, Option<f64>, Option<f64>, Option<f64>,
Option<i64>, Option<i64>,
)>(
"SELECT a.hostname, m.agent_id,
m.cpu_percent, m.ram_percent, m.disk_percent, m.temperature_c,
m.net_rx_bps, m.net_tx_bps
FROM metrics m JOIN agents a ON a.id = m.agent_id",
)
.fetch_all(&db)
.await?;
let mut out = String::with_capacity(2048);
macro_rules! gauge {
($name:expr, $help:expr, $type:expr) => {
out.push_str(&format!(
"# HELP sentinelmesh_{} {}\n# TYPE sentinelmesh_{} {}\n",
$name, $help, $name, $type
));
};
}
gauge!("cpu_percent", "Utilisation CPU en pourcentage", "gauge");
gauge!("ram_percent", "Utilisation RAM en pourcentage", "gauge");
gauge!("disk_percent", "Utilisation disque en pourcentage", "gauge");
gauge!("temperature_c", "Température CPU/système en Celsius", "gauge");
gauge!("net_rx_bps", "Débit réseau entrant en octets/s", "gauge");
gauge!("net_tx_bps", "Débit réseau sortant en octets/s", "gauge");
for (hostname, agent_id, cpu, ram, disk, temp, rx, tx) in &rows {
let lbl = format!("agent=\"{agent_id}\",hostname=\"{hostname}\"");
let push = |name: &str, val: f64| format!("sentinelmesh_{name}{{{lbl}}} {val:.2}\n");
if let Some(v) = cpu { out.push_str(&push("cpu_percent", *v)); }
if let Some(v) = ram { out.push_str(&push("ram_percent", *v)); }
if let Some(v) = disk { out.push_str(&push("disk_percent", *v)); }
if let Some(v) = temp { out.push_str(&push("temperature_c", *v)); }
if let Some(v) = rx { out.push_str(&push("net_rx_bps", *v as f64)); }
if let Some(v) = tx { out.push_str(&push("net_tx_bps", *v as f64)); }
}
Ok((
[(header::CONTENT_TYPE, "text/plain; version=0.0.4; charset=utf-8")],
out,
))
}