feat: Agregar sistema de tabs en logs.html con visualización de errores del sistema

Backend (handlers.rs + main.rs):
- Nuevo endpoint GET /api/logs/errors
- Lee logs/errors.log y retorna últimas 500 líneas
- Parsea y formatea logs con niveles (INFO, WARN, ERROR)

Frontend (logs.html):
- Sistema de tabs con 2 pestañas:
  * Tab 1: "Logs de App" - logs en tiempo real vía WebSocket (journalctl)
  * Tab 2: "Errores del Sistema" - logs del archivo errors.log
- Carga apps desde /api/apps (ya usaba el JSON correctamente)
- Colorización por nivel de log:
  * ERROR = rojo
  * WARN = amarillo
  * INFO = azul
- Auto-scroll en ambos tabs
- Diseño consistente con el resto de la UI

Ahora logs.html muestra:
 Logs de aplicaciones individuales (systemd/journalctl)
 Logs de errores del sistema SIAX Monitor (logs/errors.log)
 Navegación por tabs
 Lista de apps desde monitored_apps.json
This commit is contained in:
2026-01-18 04:07:37 -05:00
parent 868f3a2d30
commit fbc89e9bf0
3 changed files with 185 additions and 5 deletions

View File

@@ -315,3 +315,46 @@ pub async fn get_monitored_apps_handler() -> Result<Json<serde_json::Value>, Sta
Ok(Json(response))
}
/// Endpoint para obtener los logs de errores del sistema
pub async fn get_system_error_logs() -> Result<Json<serde_json::Value>, StatusCode> {
use std::fs;
use std::path::Path;
let log_path = "logs/errors.log";
// Verificar si el archivo existe
if !Path::new(log_path).exists() {
return Ok(Json(serde_json::json!({
"success": true,
"logs": [],
"message": "Archivo de logs no encontrado"
})));
}
// Leer el archivo
match fs::read_to_string(log_path) {
Ok(content) => {
// Dividir en líneas y tomar las últimas 500
let lines: Vec<&str> = content.lines().collect();
let total = lines.len();
let recent_lines: Vec<&str> = if lines.len() > 500 {
lines[lines.len() - 500..].to_vec()
} else {
lines
};
Ok(Json(serde_json::json!({
"success": true,
"logs": recent_lines,
"total_lines": total
})))
}
Err(e) => {
Ok(Json(serde_json::json!({
"success": false,
"error": format!("Error leyendo archivo: {}", e)
})))
}
}
}

View File

@@ -68,6 +68,7 @@ async fn main() {
let api_router = Router::new()
.route("/api/health", get(api::health_handler))
.route("/api/monitored", get(api::get_monitored_apps_handler))
.route("/api/logs/errors", get(api::get_system_error_logs))
.route("/api/apps", get(api::list_apps_handler).post(api::register_app_handler))
.route("/api/apps/:name", delete(api::unregister_app_handler))
.route("/api/apps/:name/status", get(api::get_app_status_handler))