per-host health graph with response times

This commit is contained in:
4cuck committed 2025-08-12 15:50:59 +02:00
1 parent 7b736f09bf
commit 7d044b998d
2 files changed
+42 -7

No files matched your search

+29 -2
View File
@@ -4,8 +4,6 @@ use sea_orm::{entity::prelude::*, FromQueryResult};
use sea_query::{Alias, Order, Query, SimpleExpr};
use serde::Serialize;
use crate::check_errors;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)]
#[sea_orm(table_name = "health_check")]
pub struct Model {
@@ -78,6 +76,35 @@ impl HealthyAmount {
}
}
#[derive(Debug, FromQueryResult, Serialize)]
pub struct ResponseTimeStat {
pub time: i64,
pub resp_time: Option<i64>,
pub healthy: bool,
}
impl ResponseTimeStat {
/// Fetch the response time + alive for a host in the specified from - to region or over all time
pub async fn fetch(
db: &DatabaseConnection,
from: Option<DateTimeUtc>,
to: Option<DateTimeUtc>,
host: i32,
) -> Result<Vec<Self>, DbErr> {
let builder = db.get_database_backend();
let mut stmt: sea_query::SelectStatement = Query::select();
stmt.column(self::Column::Time)
.column(self::Column::Healthy)
.column(self::Column::RespTime)
.and_where(self::Column::Host.eq(host))
.from(self::Entity);
if let (Some(from), Some(to)) = (from, to) {
stmt.and_where(self::Column::Time.between(from.timestamp(), to.timestamp()));
}
Self::find_by_statement(builder.build(&stmt)).all(db).await
}
}
#[cfg(test)]
mod test {
+13 -5
View File
@@ -8,7 +8,7 @@ use axum::{
};
use chrono::{TimeZone, Utc};
use entities::{
health_check,
health_check::{self, ResponseTimeStat},
host_overrides::{
self,
keys::{HostOverrides, LOCKED_FALSE, LOCKED_TRUE},
@@ -45,20 +45,28 @@ pub async fn health_csv_api(
session: Session,
) -> Result<axum::response::Response> {
let (host, _login) = get_specific_login_host(instance, &session, db).await?;
// TODO: Fetch request times and show an additional(?) red dot for failed requests"
// Nächstes mal:
// Fetch request times and show an additional(?) red dot for failed requests"
// Siehe globale? API mit response times
let start = std::time::Instant::now();
let healthy_data = health_check::HealthyAmount::fetch(db, None, None, Some(&[host.id])).await?;
let healthy_data = ResponseTimeStat::fetch(db, None, None, host.id).await?;
let queried = std::time::Instant::now();
let mut data = String::with_capacity((4 + 3 + 3 + 3 + 3 + 3 + 4) * healthy_data.len());
data.push_str("Date,Healthy,Dead\n");
data.push_str("Date,Healthy Rsp Time,Dead Rsp Time\n");
for entry in healthy_data {
let time = Utc
.timestamp_opt(entry.time, 0)
.unwrap()
.format("%Y-%m-%dT%H:%M:%SZ");
writeln!(&mut data, "{time},{},{}", entry.alive, entry.dead)
let (rsp_healthy, rsp_dead) = match (entry.resp_time, entry.healthy) {
(None, true) => (-1, 0), // no respons etime but healthy/unhealthy
(None, false) => (0, -1), // we don't really expect thse two cases and return -1
(Some(time), true) => (time, 0),
(Some(time), false) => (0, time),
};
writeln!(&mut data, "{time},{},{}", rsp_healthy, rsp_dead)
.map_err(|e| ServerError::CSV(e.to_string()))?;
}
let formatted = std::time::Instant::now();