diff --git a/entities/src/health_check.rs b/entities/src/health_check.rs index e2a5aed..ace474c 100644 --- a/entities/src/health_check.rs +++ b/entities/src/health_check.rs @@ -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, + 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, + to: Option, + host: i32, + ) -> Result, 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 { diff --git a/server/src/admin/stats.rs b/server/src/admin/stats.rs index 0a7323d..ce685e9 100644 --- a/server/src/admin/stats.rs +++ b/server/src/admin/stats.rs @@ -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 { 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();