Skip to content

Plataforma técnica · Orchestrator

Monitoring Dashboard

Orchestrator Command Monitoring

MonitoringService es el servicio del dominio Command que alimenta el dashboard ejecutivo del Command Center. Resume tenants, usuarios y salud del servidor en una sola llamada.

ConceptoVive enMide
MonitoringService (esta pág.)domain/command/MonitoringService.tsSnapshot agregado para dashboard humano.
metricsMiddleware + /metricsmiddleware/metrics.tsCounters/gauges/histograms para Prometheus.
auditLoggerlib/audit.tsTrail forense de mutaciones y auth.

Este servicio lee de monitoring.v_dashboard_summary (que a su vez agrega columnas que el audit log y el metrics middleware escriben). Es la capa de presentación sobre la infraestructura cross-cutting de observabilidad.

DashboardSummary:

CampoTipoOrigen
total_tenantsnumberv_dashboard_summary (DB).
active_tenantsnumberv_dashboard_summary (DB).
active_databasesnumberv_dashboard_summary (DB).
total_usersnumberv_dashboard_summary (DB).
active_usersnumberv_dashboard_summary (DB).
active_sessionsnumberv_dashboard_summary (DB).
system_health.cpu_load_pctnumbersysteminformation.currentLoad()vivo.
system_health.memory_usage_pctnumbersysteminformation.mem()vivo.
system_health.disk_usage_pctnumbersysteminformation.fsSize() (primera unidad) — vivo.
system_health.active_connectionsnumberAproximación: igual a active_users (placeholder).
system_health.failed_jobs_last_24hnumberv_dashboard_summary (DB).
system_health.api_errors_last_24hnumberv_dashboard_summary (DB).
flowchart LR
  R["GET /api/monitoring"]
  S["MonitoringService.getSummary()"]
  REP["MonitoringRepository"]
  V[("monitoring.v_dashboard_summary")]
  SI["systeminformation"]
  OS["sistema operativo<br/>(CPU · RAM · Disco)"]

  R --> S
  S --> REP --> V
  S --> SI --> OS
  S -. merge .-> R

getSummary() lanza ambas lecturas en paralelo (Promise.all sobre [currentLoad, mem, fsSize]) y mezcla con el resultado de la vista. Si la vista no existe o falla, el servicio degrada a solo OS metrics + vista vacía. Si systeminformation falla, devuelve solo la vista.

Terminal window
curl -b "sid=$JWT" http://localhost:8000/api/monitoring

Respuesta de ejemplo:

GET /api/monitoring
{
"total_tenants": 12,
"active_tenants": 11,
"active_databases": 11,
"total_users": 45,
"active_users": 23,
"active_sessions": 8,
"system_health": {
"cpu_load_pct": 14,
"memory_usage_pct": 62,
"disk_usage_pct": 41,
"active_connections": 23,
"failed_jobs_last_24h": 0,
"api_errors_last_24h": 3
}
}

Si la vista monitoring.v_dashboard_summary aún no se ha creado en la base, el endpoint devuelve todos los contadores en cero (no falla con 500) — útil durante setup inicial:

Fallback (vista no creada)
{
"total_tenants": 0,
"active_tenants": 0,
"total_users": 0,
"active_sessions": 0,
"system_health": {
"disk_usage_pct": 0,
"cpu_load_pct": 0,
"memory_usage_pct": 0
}
}
FallaComportamiento
Vista de DB no existeDevuelve ceros + advertencia en stdout.
systeminformation fallaDevuelve solo la parte de DB (sin cpu/mem/disk).
Conexión a centralPool caeEl endpoint retorna 500 con shape estándar de error.

systeminformation hace syscalls al SO y puede tardar 100-300ms en algunas plataformas (especialmente fsSize). El endpoint es read-only y no cacheado: si el dashboard de Sevastopol hace polling cada 5s, espera ese costo. Si se vuelve un problema, opciones:

  1. Cachear el resultado en memoria por N segundos en MonitoringService.
  2. Mover el polling de systeminformation a un loop separado que actualice gauges y leer desde el cache.
  3. Reemplazar el polling del UI por SSE o WebSocket desde un colector dedicado.

Ninguna está implementada — la actual asume baja frecuencia de consulta (operador humano abriendo el dashboard, no auto-refresh agresivo).

La definición de la vista vive en mother (PostgreSQL del esquema monitoring). Esta página documenta el contrato de salida que consume MonitoringRepository.getDashboardSummary, no el SQL de la vista. Ver el repositorio Mother para el DDL.

En el código actual:

active_connections: dbSummary.active_users // approximation

Si se necesita el valor real de conexiones de Postgres, leer pg_stat_activity y sumar COUNT(*) WHERE state = 'active'. Implementación pendiente.