- reports/0001-2026-06-07-unibus-grafana-monitoring.md - reports/0008-2026-06-07-unibus-admin-users-wired.md - reports/0008-2026-06-07-unibus-decentralization-audit.md - reports/0009-2026-06-07-unibus-cluster-hardening.md - reports/0010-2026-06-07-unibus-android-native.md - reports/0011-2026-06-07-unibus-cluster-deploy.md - reports/0012-2026-06-07-unibus-deploy-gaps-closed.md - reports/0013-2026-06-07-unibus-admin-panel.md - reports/0014-2026-06-07-unibus-users-http-admin-api.md - reports/0015-2026-06-07-unibus-web-wired.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.2 KiB
Report 0001 — Monitorización de unibus en Grafana/VictoriaMetrics
- Fecha: 07/06/2026
- Autor: agente (Claude Opus 4.8)
- Ámbito:
projects/fleet_monitoring/(exporter + dashboard + deploy) + 1 función nueva en el registry (functions/infra/). Solo lectura deprojects/message_bus/apps/unibus/(endpoint/healthz+ CA). - Estado: done (métricas de
/healthz); gap declarado en métricas profundas NATS/JetStream.
Resumen
Se añadió monitorización del cluster de mensajería unibus (NATS+JetStream, 3 nodos: magnus,
homer, datardos) a la stack de Grafana/VictoriaMetrics que ya corre en magnus, sin instrumentar
el bus. Un nuevo daemon unibus_exporter sondea el endpoint público de salud de cada nodo
(GET https://<nodo>:8470/healthz, TLS verificado con la CA del cluster) en un bucle de 15 s,
traduce la respuesta a métricas Prometheus y las empuja a la VictoriaMetrics local de magnus.
Un dashboard dedicado las visualiza. No se tocó nada del código de unibus ni la stack existente
(Caddy/Gitea/VM/Grafana/fleet-agent intactos).
Qué métricas se recolectan y cómo
El /healthz de cada nodo devuelve, verificado en producción:
{"posture":{"enforce":true,"acl":true,"tls":true,"cluster":true,"store":"kv"},"status":"ok"}
De ahí se derivan estas series (labels node e instance = nombre del nodo, label común
job=unibus_exporter):
| Serie | Origen | Significado |
|---|---|---|
unibus_up |
exporter | 1 si el nodo respondió /healthz, 0 si el GET/parseo falló |
unibus_status_ok |
healthz status |
1 si status=="ok" |
unibus_posture_enforce |
healthz posture.enforce |
enforcement de auth (1/0) |
unibus_posture_acl |
healthz posture.acl |
ACL de subjects (1/0) |
unibus_posture_tls |
healthz posture.tls |
TLS del transporte (1/0) |
unibus_posture_cluster |
healthz posture.cluster |
modo cluster activo (1/0) |
unibus_store_kv |
healthz posture.store |
1 si el store es kv (JetStream KV) |
unibus_scrape_error |
exporter | 1 si el scrape de ese nodo falló |
unibus_scrape_duration_seconds |
exporter | latencia del GET /healthz |
unibus_cluster_size |
exporter (config) | nº de nodos configurados (los vivos = sum(unibus_up)) |
unibus_up=0 lo emite el exporter (no el parser) cuando el GET falla, para que un nodo caído sea
visible en Grafana, no simplemente ausente.
Componentes entregados
Función del registry — parse_unibus_health_go_infra
functions/infra/parse_unibus_health.go+.md+_test.go(grupofleet-metrics, tagsunibus).func ParseUnibusHealth(node string, body []byte) ([]PromSample, error)— pura de transformación (clasificadaimpuresolo por el error de unmarshal). Tests golden/edge/error.- Nota de proceso: el prompt pedía delegar esta función a
fn-constructor, pero ese subagent_type no existe en este entorno. Tras confirmar con el usuario ("crear en el registry"), se creó a mano siguiendo el flujo (archivos + tests +fn index).
App — unibus_exporter (sub-repo Gitea propio)
projects/fleet_monitoring/apps/unibus_exporter/:main.go,config.go,unibus.example.json,systemd/unibus-exporter.service,app.md,.gitignore.- Compone
parse_unibus_health+format_prom_exposition+push_prom_remotedel registry (no reescribe push ni formato). Config JSON; secretos (CA, basic-auth) fuera de argv. Verifica TLS siempre contra la CA del cluster (sinInsecureSkipVerify). git init -b master+ commit inicial hecho (apps/* está gitignored en el project; sin sub-repo el código se perdería). Falta crear el repo Gitea remoto: lo hará/full-git-push.
Dashboard — unibus-cluster.json
projects/fleet_monitoring/hub/dashboards/unibus-cluster.json(formato de losfleet-*.json, datasourcevictoriametrics, carpeta Fleet, uidunibus-cluster, 9 paneles): nodos up, cluster size, nodos caídos, posture homogénea segura, up/down por nodo, matriz de posture por nodo (state-timeline enforce/acl/tls/cluster/store-kv × 3 nodos), latencia de scrape y tabla de estado por nodo. Panel "Meta-leader" preparado (muestra n/d sin métricas NATS).
Deploy — deploy_unibus_exporter.sh
projects/fleet_monitoring/hub/deploy_unibus_exporter.sh: compila el binario linux/amd64, sube binario + CA del cluster a magnus (/opt/unibus-exporter,/etc/unibus-exporter/ca.crtchmod 600 la config) e instala el servicio systemd apuntando ahttp://127.0.0.1:8428/...(VM local, sin auth porque corre en el propio hub).
Verificación (evidencia ejecutable)
1. Acceso y healthz de los 3 nodos (CA del cluster por path):
$ curl -s --cacert .../deploy/tls/ca.crt https://135.125.201.30:8470/healthz
{"posture":{"enforce":true,"acl":true,"tls":true,"cluster":true,"store":"kv"},"status":"ok"}
(idéntico en homer 141.94.69.66 y datardos 51.91.100.142)
2. Tests de la función:
$ go test -tags fts5 -run ParseUnibusHealth ./functions/infra/
ok fn-registry/functions/infra 0.004s
$ ./fn index # → "Indexed 1450 functions ..."; ./fn show parse_unibus_health_go_infra → OK
3. Exporter build + scrape/push único de prueba (local → VM):
$ ./unibus_exporter -config <test> -once
unibus_exporter starting: nodes=3 hub="https://metrics-…/api/v1/import/prometheus" interval=15s
pushed 28 samples for 3 nodes # 1 cluster_size + 3 nodos × 9 series
4. Daemon systemd en magnus:
$ systemctl is-active unibus-exporter → active
$ systemctl is-enabled unibus-exporter → enabled
$ journalctl -u unibus-exporter → "pushed 28 samples for 3 nodes"
5. Series en VictoriaMetrics (magnus, 127.0.0.1:8428):
sum(unibus_up) = 3
unibus_cluster_size = 3
count(unibus_up==1) = 3
unibus_posture_enforce: magnus=1 homer=1 datardos=1 (job=unibus_exporter)
unibus_store_kv: magnus=1 homer=1 datardos=1
unibus_scrape_duration_seconds: magnus≈4ms homer≈32ms datardos≈19ms
6. Dashboard en Grafana (visto en el navegador):
https://grafana-…/d/unibus-cluster— carpeta Fleet, 9 paneles renderizando datos reales.- Nodos up: 3 · Cluster size: 3 · Nodos caídos: 0 · Posture homogénea segura: OK (enforce+acl+tls+cluster+kv) · matriz de posture: 15 celdas en verde · tabla de estado por nodo con ✓ en up/enforce/acl/tls.
- Captura:
unibus-grafana-monitoring-dashboard.png(junto a este report). - API:
GET /api/dashboards/uid/unibus-cluster→dashboard CARGADO: unibus — Cluster | folder: Fleet | paneles: 9.
Gaps / pendientes
- Métricas profundas NATS/JetStream (msgs/s, conexiones, KV bucket msgs, RAFT leader por
stream,
NRestarts) — NO incluidas, gap recomendado. La vía es el monitoring embebido de NATS (puerto 8222), que se confirmó cerrado en los 3 nodos en producción (curl 127.0.0.1:8222/varz→ CLOSED en magnus/homer/dd). Activarlo (bindeado a 127.0.0.1 + scrape local, o sacar/jszpor SSH) exige tocar la config/unit de los nodos del cluster, que además están siendo trabajados por otros agentes ahora mismo. Se decidió no forzarlo por riesgo en producción. Para abordarlo después: añadirUNIBUS_NATS_DEBUG/equivalente bindeado a loopback en cada nodo (cambio aditivo, coordinado conunibus/deploy/cluster/), un scrape local del/jsz+/varzy nuevas seriesunibus_jsz_*. El panel "Meta-leader" del dashboard ya está preparado para cuando existaunibus_meta_leader. unibus_cluster_sizerefleja el nº de nodos configurados en el exporter (3), no un recuento que el bus reporte (healthz no lo expone). Los nodos vivos se ven consum(unibus_up).- Commit en el repo padre
fn_registrysin pushear (a propósito): la función nueva quedó commiteada en local (82f1f1bd, master ahead 1) pero no se hizo push del padre, para respetar el aislamiento pedido. El humano debería revisarlo y pushearlo (junto confn indexpara regenerarregistry.db, que está gitignored). - Repo Gitea del exporter:
apps/unibus_exportertiene sugit init+ commit local pero aún no tiene remoto en Gitea;/full-git-pushlo creará (dataforge/unibus_exporter). - Vida útil (DoD capa 3): validado funcionalmente hoy; falta la ventana de uso real ≥7 días.