feat: Sistema de monitoreo base con logging y configuración dinámica
- Implementado monitor de procesos Node.js con detección automática - Sistema de logging con niveles (Info, Warning, Error, Critical) - ConfigManager para gestión dinámica de apps monitoreadas - Interfaz web básica con escaneo de procesos - Integración con API central para reportar estados - User-Agent tracking para identificación de agentes - Persistencia de configuración en JSON - Logs almacenados en archivo con rotación - Sistema modular: monitor, interface, logger, config Estructura: - src/main.rs: Orquestador principal - src/monitor.rs: Monitoreo de procesos y envío a API - src/interface.rs: Servidor web Axum con endpoints - src/logger.rs: Sistema de logging a archivo y consola - src/config.rs: Gestión de configuración persistente - web/: Templates HTML para interfaz web - config/: Configuración de apps monitoreadas - logs/: Archivos de log del sistema Features implementadas: ✅ Detección automática de procesos Node.js ✅ Monitoreo de CPU y RAM por proceso ✅ Reportes periódicos a API central (cada 60s) ✅ Interfaz web en puerto 8080 ✅ Logs estructurados con timestamps ✅ Configuración dinámica sin reinicio ✅ Script de despliegue automatizado Próximos pasos: - Integración con systemd para control de procesos - Dashboard mejorado con cards de apps - Logs en tiempo real vía WebSocket - Start/Stop/Restart de aplicaciones
This commit is contained in:
78
web/index.html
Normal file
78
web/index.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>SIAX Emergency Panel</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
padding: 40px;
|
||||
}
|
||||
h1 {
|
||||
color: #3b82f6;
|
||||
}
|
||||
.status-online {
|
||||
color: #22c55e;
|
||||
font-weight: bold;
|
||||
}
|
||||
.server-info {
|
||||
color: #94a3b8;
|
||||
}
|
||||
.button-container {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
.btn-primary {
|
||||
background: #3b82f6;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
.btn-success {
|
||||
background: #22c55e;
|
||||
}
|
||||
.btn-success:hover {
|
||||
background: #16a34a;
|
||||
}
|
||||
.btn-warning {
|
||||
background: #f59e0b;
|
||||
}
|
||||
.btn-warning:hover {
|
||||
background: #d97706;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🚨 SIAX EMERGENCY PANEL</h1>
|
||||
<p>Estado del Agente: <span class="status-online">● ONLINE</span></p>
|
||||
<p class="server-info">Servidor: {{SERVER_NAME}}</p>
|
||||
|
||||
<div class="button-container">
|
||||
<a href="/scan" class="btn btn-primary">
|
||||
🔍 Escanear Sistema
|
||||
</a>
|
||||
|
||||
<a href="/select" class="btn btn-success">
|
||||
⚙️ Gestionar Procesos
|
||||
</a>
|
||||
|
||||
<a href="/logs" class="btn btn-warning">
|
||||
📋 Ver Logs
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
246
web/logs.html
Normal file
246
web/logs.html
Normal file
@@ -0,0 +1,246 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Logs del Sistema - SIAX</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: 'Courier New', monospace;
|
||||
padding: 40px;
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
color: #3b82f6;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.controls {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
.btn-primary {
|
||||
background: #3b82f6;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
.btn-danger {
|
||||
background: #ef4444;
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background: #dc2626;
|
||||
}
|
||||
.btn-secondary {
|
||||
background: #64748b;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: #475569;
|
||||
}
|
||||
.stats {
|
||||
background: #1e293b;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.stat-info {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
border: 1px solid #3b82f6;
|
||||
}
|
||||
.stat-warning {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border: 1px solid #f59e0b;
|
||||
}
|
||||
.stat-error {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border: 1px solid #ef4444;
|
||||
}
|
||||
.stat-critical {
|
||||
background: rgba(220, 38, 38, 0.1);
|
||||
border: 1px solid #dc2626;
|
||||
}
|
||||
.stat-number {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.log-entry {
|
||||
background: #1e293b;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.log-info {
|
||||
border-left-color: #3b82f6;
|
||||
}
|
||||
.log-warning {
|
||||
border-left-color: #f59e0b;
|
||||
}
|
||||
.log-error {
|
||||
border-left-color: #ef4444;
|
||||
}
|
||||
.log-critical {
|
||||
border-left-color: #dc2626;
|
||||
background: rgba(220, 38, 38, 0.1);
|
||||
}
|
||||
.log-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.log-timestamp {
|
||||
color: #94a3b8;
|
||||
font-size: 11px;
|
||||
}
|
||||
.log-level {
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.log-module {
|
||||
color: #60a5fa;
|
||||
}
|
||||
.log-message {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.log-details {
|
||||
background: #0f172a;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-top: 8px;
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
}
|
||||
.no-logs {
|
||||
background: #1e293b;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
border-radius: 8px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
.filter-bar {
|
||||
background: #1e293b;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.filter-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.filter-checkbox input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.filter-checkbox label {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>📋 Logs del Sistema SIAX</h1>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="location.reload()" class="btn btn-primary">🔄 Refrescar</button>
|
||||
<button onclick="clearLogs()" class="btn btn-danger">🗑️ Limpiar Logs</button>
|
||||
<a href="/" class="btn btn-secondary">← Volver al Panel</a>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
{{STATS}}
|
||||
</div>
|
||||
|
||||
<div class="filter-bar">
|
||||
<span style="color: #60a5fa; font-weight: bold;">Filtrar por nivel:</span>
|
||||
<div class="filter-checkbox">
|
||||
<input type="checkbox" id="filter-info" checked onchange="filterLogs()">
|
||||
<label for="filter-info">ℹ️ Info</label>
|
||||
</div>
|
||||
<div class="filter-checkbox">
|
||||
<input type="checkbox" id="filter-warning" checked onchange="filterLogs()">
|
||||
<label for="filter-warning">⚠️ Warning</label>
|
||||
</div>
|
||||
<div class="filter-checkbox">
|
||||
<input type="checkbox" id="filter-error" checked onchange="filterLogs()">
|
||||
<label for="filter-error">❌ Error</label>
|
||||
</div>
|
||||
<div class="filter-checkbox">
|
||||
<input type="checkbox" id="filter-critical" checked onchange="filterLogs()">
|
||||
<label for="filter-critical">🔥 Critical</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logs-container">
|
||||
{{LOGS}}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function clearLogs() {
|
||||
if (confirm('¿Estás seguro de que quieres eliminar todos los logs?')) {
|
||||
fetch('/clear-logs', { method: 'POST' })
|
||||
.then(() => location.reload())
|
||||
.catch(err => alert('Error al limpiar logs: ' + err));
|
||||
}
|
||||
}
|
||||
|
||||
function filterLogs() {
|
||||
const showInfo = document.getElementById('filter-info').checked;
|
||||
const showWarning = document.getElementById('filter-warning').checked;
|
||||
const showError = document.getElementById('filter-error').checked;
|
||||
const showCritical = document.getElementById('filter-critical').checked;
|
||||
|
||||
const logs = document.querySelectorAll('.log-entry');
|
||||
logs.forEach(log => {
|
||||
const level = log.dataset.level;
|
||||
let show = false;
|
||||
|
||||
if (level === 'info' && showInfo) show = true;
|
||||
if (level === 'warning' && showWarning) show = true;
|
||||
if (level === 'error' && showError) show = true;
|
||||
if (level === 'critical' && showCritical) show = true;
|
||||
|
||||
log.style.display = show ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-refresh cada 30 segundos
|
||||
setTimeout(() => location.reload(), 30000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
71
web/scan.html
Normal file
71
web/scan.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Scan Results - SIAX</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
padding: 40px;
|
||||
}
|
||||
h1 {
|
||||
color: #3b82f6;
|
||||
}
|
||||
.process {
|
||||
background: #1e293b;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #3b82f6;
|
||||
}
|
||||
.pid {
|
||||
color: #22c55e;
|
||||
font-weight: bold;
|
||||
}
|
||||
.name {
|
||||
color: #60a5fa;
|
||||
}
|
||||
.cpu {
|
||||
color: #f59e0b;
|
||||
}
|
||||
.mem {
|
||||
color: #8b5cf6;
|
||||
}
|
||||
.path {
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.summary {
|
||||
color: #22c55e;
|
||||
font-size: 18px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.no-results {
|
||||
background: #7f1d1d;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #ef4444;
|
||||
}
|
||||
.back-btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #64748b;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.back-btn:hover {
|
||||
background: #475569;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔍 Escaneo de Procesos Node.js</h1>
|
||||
{{CONTENT}}
|
||||
<a href="/" class="back-btn">← Volver al Panel</a>
|
||||
</body>
|
||||
</html>
|
||||
160
web/select.html
Normal file
160
web/select.html
Normal file
@@ -0,0 +1,160 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Gestionar Procesos - SIAX</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
padding: 40px;
|
||||
}
|
||||
h1 {
|
||||
color: #3b82f6;
|
||||
}
|
||||
h2 {
|
||||
color: #60a5fa;
|
||||
margin-top: 40px;
|
||||
}
|
||||
.process-item {
|
||||
background: #1e293b;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.process-info {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.pid {
|
||||
color: #22c55e;
|
||||
font-weight: bold;
|
||||
}
|
||||
.path {
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.select-btn {
|
||||
padding: 8px 16px;
|
||||
background: #22c55e;
|
||||
border: none;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
.select-btn:hover {
|
||||
background: #16a34a;
|
||||
}
|
||||
.form-section {
|
||||
background: #1e293b;
|
||||
padding: 25px;
|
||||
border-radius: 12px;
|
||||
margin-top: 20px;
|
||||
border: 2px solid #3b82f6;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
color: #60a5fa;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #0f172a;
|
||||
border: 2px solid #475569;
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
small {
|
||||
color: #94a3b8;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.submit-btn {
|
||||
padding: 12px 24px;
|
||||
background: #3b82f6;
|
||||
border: none;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.submit-btn:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
.back-btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #64748b;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.back-btn:hover {
|
||||
background: #475569;
|
||||
}
|
||||
.no-results {
|
||||
background: #7f1d1d;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #ef4444;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>⚙️ Gestionar Procesos a Monitorear</h1>
|
||||
|
||||
<h2>📋 Procesos Node.js Detectados</h2>
|
||||
{{PROCESSES_LIST}}
|
||||
|
||||
<h2>➕ Agregar Proceso Personalizado</h2>
|
||||
<div class="form-section">
|
||||
<form method="POST" action="/add-process">
|
||||
<div class="form-group">
|
||||
<label for="app_name">Nombre de la Aplicación:</label>
|
||||
<input type="text" id="app_name" name="app_name" placeholder="Ej: app_tareas, fidelizacion, mi-api" required>
|
||||
<small>💡 Este nombre se usará para identificar el proceso en el directorio de trabajo</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="port">Puerto:</label>
|
||||
<input type="number" id="port" name="port" placeholder="Ej: 3000, 3001, 8080" required>
|
||||
<small>💡 Puerto donde corre la aplicación</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="submit-btn">💾 Guardar y Monitorear</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<a href="/" class="back-btn">← Volver al Panel</a>
|
||||
|
||||
<script>
|
||||
function fillForm(appName, pid) {
|
||||
document.getElementById('app_name').value = appName;
|
||||
document.querySelector('.form-section').scrollIntoView({ behavior: 'smooth' });
|
||||
document.querySelector('.form-section').style.borderColor = '#22c55e';
|
||||
setTimeout(() => {
|
||||
document.querySelector('.form-section').style.borderColor = '#3b82f6';
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
58
web/success.html
Normal file
58
web/success.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="3;url=/select">
|
||||
<title>Proceso Agregado - SIAX</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.success {
|
||||
background: #064e3b;
|
||||
border: 2px solid #22c55e;
|
||||
padding: 40px;
|
||||
border-radius: 16px;
|
||||
max-width: 500px;
|
||||
margin: 100px auto;
|
||||
}
|
||||
h1 {
|
||||
color: #22c55e;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.details {
|
||||
background: #0f172a;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
.label {
|
||||
color: #60a5fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
.redirect-msg {
|
||||
color: #94a3b8;
|
||||
margin-top: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="success">
|
||||
<h1>✅ Proceso Agregado Exitosamente</h1>
|
||||
<p style="color:#94a3b8;">El proceso será monitoreado en el próximo ciclo</p>
|
||||
|
||||
<div class="details">
|
||||
<p><span class="label">Aplicación:</span> {{APP_NAME}}</p>
|
||||
<p><span class="label">Puerto:</span> {{PORT}}</p>
|
||||
</div>
|
||||
|
||||
<p class="redirect-msg">Redirigiendo en 3 segundos...</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user