Consolidate HTTP checking and improve display formatting

- Change site latency timeout from 5s to 2s for faster error detection
- Replace curl with reqwest for external connectivity checks (consistent timeouts)
- Remove unused gitea-specific monitoring functionality
- Update dashboard: show 'unreachable' for latency > 2000ms, add arrows (→) between site and latency
- Add percentage signs to CPU metrics display
- All HTTP requests now use reqwest with 2-second timeouts
This commit is contained in:
Christoffer Martinsson 2025-10-14 22:24:22 +02:00
parent 819ca4ad73
commit 0cb69ea8fa
2 changed files with 21 additions and 63 deletions

View File

@ -651,7 +651,6 @@ impl ServiceCollector {
"postgresql" | "postgres" => self.get_postgres_connections().await.map(|s| vec![s]),
"mysql" | "mariadb" => self.get_mysql_connections().await.map(|s| vec![s]),
"redis" | "redis-immich" => self.get_redis_info().await.map(|s| vec![s]),
"gitea" => self.get_gitea_info().await.map(|s| vec![s]),
"immich-server" => self.get_immich_info().await.map(|s| vec![s]),
"vaultwarden" => self.get_vaultwarden_info().await.map(|s| vec![s]),
"unifi" => self.get_unifi_info().await.map(|s| vec![s]),
@ -843,7 +842,7 @@ impl ServiceCollector {
// Create HTTP client with short timeout
let client = match reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.timeout(Duration::from_secs(2))
.build()
{
Ok(client) => client,
@ -1050,31 +1049,28 @@ impl ServiceCollector {
}
async fn check_site_accessibility(&self, hostname: &str) -> bool {
// Create HTTP client with same timeout as site latency checks
let client = match reqwest::Client::builder()
.timeout(Duration::from_secs(2))
.build()
{
Ok(client) => client,
Err(_) => return false,
};
// Try HTTPS first, then HTTP
for scheme in ["https", "http"] {
let url = format!("{}://{}", scheme, hostname);
match tokio::time::timeout(
Duration::from_secs(5),
Command::new("/run/current-system/sw/bin/curl")
.args(["-s", "-I", "--max-time", "3", &url])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
).await {
Ok(Ok(output)) if output.status.success() => {
let response = String::from_utf8_lossy(&output.stdout);
// Check for successful HTTP status codes
if response.contains("HTTP/") && (
response.contains(" 200 ") ||
response.contains(" 301 ") ||
response.contains(" 302 ") ||
response.contains(" 403 ") // Some sites return 403 but are still "accessible"
) {
match client.get(&url).send().await {
Ok(response) => {
let status = response.status().as_u16();
// Check for successful HTTP status codes (same logic as before)
if status == 200 || status == 301 || status == 302 || status == 403 {
return true;
}
}
_ => continue,
Err(_) => continue,
}
}
@ -1139,44 +1135,6 @@ impl ServiceCollector {
None
}
async fn get_gitea_info(&self) -> Option<String> {
// Try to get gitea stats from API (if accessible)
let output = Command::new("/run/current-system/sw/bin/curl")
.args(["-s", "-f", "-m", "2", "http://localhost:3000/api/v1/repos/search?limit=1"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.await
.ok()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&stdout) {
if let Some(total_count) = json["total_count"].as_u64() {
return Some(format!("{} repositories", total_count));
}
}
}
// Fallback: check HTTP connections on port 3000
let output = Command::new("/run/current-system/sw/bin/ss")
.args(["-tn", "state", "established", "dport", "= :3000"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.await
.ok()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let connection_count = stdout.lines().count().saturating_sub(1);
if connection_count > 0 {
return Some(format!("{} connections", connection_count));
}
}
None
}
async fn get_immich_info(&self) -> Option<String> {
// Check HTTP connections - Immich runs on port 8084 (from nginx proxy config)

View File

@ -110,9 +110,9 @@ fn render_metrics(
let service_name_with_latency = if let Some(parent) = &svc.sub_service {
if parent == "nginx" {
match &svc.latency_ms {
Some(latency) if *latency >= 5000.0 => format!("{} unreachable", svc.name), // Timeout (5s+)
Some(latency) => format!("{} {:.0}ms", svc.name, latency),
None => format!("{} unreachable", svc.name), // Connection failed
Some(latency) if *latency >= 2000.0 => format!("{} unreachable", svc.name), // Timeout (2s+)
Some(latency) => format!("{} {:.0}ms", svc.name, latency),
None => format!("{} unreachable", svc.name), // Connection failed
}
} else {
svc.name.clone()
@ -178,9 +178,9 @@ fn format_memory_value(used: f32, quota: f32) -> String {
fn format_cpu_value(cpu_percent: f32) -> String {
if cpu_percent >= 0.1 {
format!("{:.1}", cpu_percent)
format!("{:.1}%", cpu_percent)
} else {
"0.0".to_string()
"0.0%".to_string()
}
}