Implement nginx site latency monitoring and improve disk usage display
Agent improvements: - Add reqwest dependency for HTTP latency testing - Implement measure_site_latency() function for nginx sites - Add latency_ms field to ServiceData structure - Measure response times for nginx sites using HEAD requests - Handle connection failures gracefully with 5-second timeout - Use HTTPS for external sites, HTTP for localhost Dashboard improvements: - Add latency_ms field to ServiceInfo structure - Display latency for nginx sites: "docker.cmtec.se 134ms" - Only show latency for nginx sub-services, not other services - Change disk usage "0" to "<1MB" for better readability The Services widget now shows: - Nginx sites with response times when measurable - Cleaner disk usage formatting for small values - Improved user experience with meaningful latency data
This commit is contained in:
@@ -3,7 +3,7 @@ use chrono::Utc;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use std::process::Stdio;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::fs;
|
||||
use tokio::process::Command;
|
||||
use tokio::time::timeout;
|
||||
@@ -129,6 +129,7 @@ impl ServiceCollector {
|
||||
is_sandbox_excluded,
|
||||
description,
|
||||
sub_service: None,
|
||||
latency_ms: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -831,6 +832,40 @@ impl ServiceCollector {
|
||||
std::env::var("UID").unwrap_or_default() == "0"
|
||||
}
|
||||
|
||||
async fn measure_site_latency(&self, site_name: &str) -> Option<f32> {
|
||||
// Construct URL from site name
|
||||
let url = if site_name.contains("localhost") || site_name.contains("127.0.0.1") {
|
||||
format!("http://{}", site_name)
|
||||
} else {
|
||||
format!("https://{}", site_name)
|
||||
};
|
||||
|
||||
// Create HTTP client with short timeout
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(5))
|
||||
.build()
|
||||
.ok()?;
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
// Make HEAD request to avoid downloading content
|
||||
match client.head(&url).send().await {
|
||||
Ok(response) => {
|
||||
let latency = start.elapsed().as_millis() as f32;
|
||||
if response.status().is_success() || response.status().is_redirection() {
|
||||
Some(latency)
|
||||
} else {
|
||||
// Site is reachable but returned error, still measure latency
|
||||
Some(latency)
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Connection failed, no latency measurement
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_nginx_sites(&self) -> Option<Vec<String>> {
|
||||
|
||||
// Get the actual nginx config file path from systemd (NixOS uses custom config)
|
||||
@@ -1320,6 +1355,9 @@ impl Collector for ServiceCollector {
|
||||
// Add nginx sites as individual sub-services
|
||||
if let Some(sites) = self.get_nginx_sites().await {
|
||||
for site in sites.iter() {
|
||||
// Measure latency for this site
|
||||
let latency = self.measure_site_latency(site).await;
|
||||
|
||||
services.push(ServiceData {
|
||||
name: site.clone(),
|
||||
status: ServiceStatus::Running, // Assume sites are running if nginx is running
|
||||
@@ -1333,6 +1371,7 @@ impl Collector for ServiceCollector {
|
||||
is_sandbox_excluded: false,
|
||||
description: None,
|
||||
sub_service: Some("nginx".to_string()),
|
||||
latency_ms: latency,
|
||||
});
|
||||
healthy += 1;
|
||||
}
|
||||
@@ -1361,6 +1400,7 @@ impl Collector for ServiceCollector {
|
||||
is_sandbox_excluded: false,
|
||||
description: None,
|
||||
sub_service: Some("docker".to_string()),
|
||||
latency_ms: None,
|
||||
});
|
||||
healthy += 1;
|
||||
}
|
||||
@@ -1385,6 +1425,7 @@ impl Collector for ServiceCollector {
|
||||
is_sandbox_excluded: false,
|
||||
description: None,
|
||||
sub_service: None,
|
||||
latency_ms: None,
|
||||
});
|
||||
tracing::warn!("Failed to collect metrics for service {}: {}", service, e);
|
||||
}
|
||||
@@ -1449,6 +1490,8 @@ struct ServiceData {
|
||||
description: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
sub_service: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
latency_ms: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
||||
Reference in New Issue
Block a user