Files
fn_registry/functions/infra/parse_nats_monitor.md
T
egutierrez 0a6d1b8d17 feat(infra): auto-commit con 6 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 01:57:00 +02:00

6.6 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, test_file_path, tests
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested test_file_path tests
parse_nats_monitor function go infra 1.0.0 impure func ParseNatsMonitor(node string, varz, connz, jsz []byte) ([]PromSample, error) Convierte las respuestas JSON del endpoint de monitoring HTTP embebido de un nats-server (puerto 8222, loopback) en una serie de PromSample lista para empujar a VictoriaMetrics. Hermana de ParseUnibusHealth pero para las métricas server-level de NATS/JetStream: msgs/s, bytes, conexiones, slow consumers, memoria RSS, start epoch (proxy de reinicios), streams/messages/bytes/memory/storage de JetStream, y por stream nats_stream_messages/bytes, nats_jetstream_raft_leader y kv_bucket_msgs para los buckets KV_. Adjunta labels node e instance a cada serie. varz es el core (error si no parsea); connz y jsz son best-effort (se omiten sin abortar). La consume el unibus_exporter de fleet_monitoring como scraper local por nodo.
prometheus
metrics
nats
jetstream
monitoring
varz
connz
jsz
kv
raft
fleet-metrics
infra
PromSample_go_infra
true error_go_core
encoding/json
fmt
strings
time
name desc
node nombre lógico del nodo (p.ej. "magnus"); se adjunta como labels node e instance a CADA serie y se compara con cluster.leader de cada stream para nats_jetstream_raft_leader
name desc
varz cuerpo JSON crudo de GET http://127.0.0.1:8222/varz; core de la función (in_msgs, out_msgs, in_bytes, out_bytes, connections, slow_consumers, subscriptions, mem, start). Si no parsea, la función devuelve error
name desc
connz cuerpo JSON crudo de GET http://127.0.0.1:8222/connz; best-effort (num_connections). Si vacío o inválido, nats_connections cae a varz.connections sin abortar
name desc
jsz cuerpo JSON crudo de GET http://127.0.0.1:8222/jsz?streams=1; best-effort (streams, messages, bytes, memory, storage y account_details[].stream_detail[]). Si vacío o inválido, se omiten sus series sin abortar. Necesita ?streams=1 para traer stream_detail
slice de PromSample con labels base {node,instance}: nats_msgs_in/out_total, nats_bytes_in/out_total, nats_connections, nats_slow_consumers, nats_mem_bytes, nats_subscriptions, nats_server_start_seconds (omitida si start no parsea), nats_jetstream_streams/messages/bytes/memory_bytes/storage_bytes; y por stream nats_stream_messages{stream}, nats_stream_bytes{stream}, nats_jetstream_raft_leader{stream} (1 si cluster.leader==node) y, para streams KV_, kv_bucket_msgs{bucket} con el prefijo KV_ recortado. Error solo si varz no es JSON válido. true functions/infra/parse_nats_monitor_test.go
TestParseNatsMonitorGolden
TestParseNatsMonitorEmptyJsz
TestParseNatsMonitorInvalidConnz
TestParseNatsMonitorInvalidVarz

parse_nats_monitor

Función de transformación (clasificada impure porque devuelve error al fallar el unmarshal del core; no hace I/O ni red por sí misma) que traduce las métricas server-level de un nats-server a series Prometheus. Es la hermana de parse_unibus_health_go_infra: aquella lee el /healthz de membershipd (posture), esta lee el monitoring embebido de NATS (puerto 8222) para las métricas profundas que /healthz no expone: msgs/s, conexiones, RAFT leader por stream, memoria, KV buckets.

Pertenece al grupo de capacidad fleet-metrics: se compone con format_prom_exposition_go_infra (serializar) y push_prom_remote_go_infra (empujar a VictoriaMetrics). La consume el unibus_exporter de fleet_monitoring en modo scraper local por nodo, que hace los tres GET y le pasa los cuerpos crudos.

Ejemplo

package main

import (
	"fmt"
	"io"
	"net/http"
	"time"

	"fn-registry/functions/infra"
)

func get(url string) []byte {
	resp, err := http.Get(url)
	if err != nil {
		return nil // best-effort: connz/jsz pueden faltar
	}
	defer resp.Body.Close()
	b, _ := io.ReadAll(resp.Body)
	return b
}

func main() {
	base := "http://127.0.0.1:8222"
	varz := get(base + "/varz")
	connz := get(base + "/connz")
	jsz := get(base + "/jsz?streams=1")

	samples, err := infra.ParseNatsMonitor("magnus", varz, connz, jsz)
	if err != nil {
		panic(err) // varz es el core: sin él no hay métricas
	}
	fmt.Print(infra.FormatPromExposition(samples, time.Now().UnixMilli()))
	// nats_msgs_in_total{instance="magnus",node="magnus"} 17 ...
	// kv_bucket_msgs{bucket="UNIBUS_users",instance="magnus",node="magnus"} 2 ...
	// nats_jetstream_raft_leader{instance="magnus",node="magnus",stream="KV_UNIBUS_users"} 1 ...
}

Cuando usarla

Úsala dentro de un exporter que monitoriza un nats-server con el monitoring HTTP embebido activado (http: 127.0.0.1:8222 en la config de NATS): tras hacer GET /varz, GET /connz y GET /jsz?streams=1 contra loopback, pasa los tres cuerpos crudos a esta función para obtener todas las series server-level del nodo. Llámala como scraper local por nodo (cada nodo expone su 8222 solo en loopback), no centralizado.

Gotchas

  • Impura por contrato: solo devuelve error si varz no es JSON válido (es el core). connz y jsz son best-effort: si vienen vacíos o no parsean, sus series se omiten sin abortar. Esto hace al scraper resistente a que un endpoint falle de forma puntual.
  • Monitoring loopback-only sin auth: el puerto 8222 de NATS no tiene autenticación; por eso debe bindearse a 127.0.0.1 y scrapearse localmente en cada nodo, nunca exponerse a la red. El push agregado a VictoriaMetrics lo hace el exporter, no esta función.
  • /jsz necesita ?streams=1 para traer account_details[].stream_detail[]. Sin ese parámetro el cuerpo trae los totales pero no el detalle por stream, y entonces no salen nats_stream_*, nats_jetstream_raft_leader ni kv_bucket_msgs.
  • nats_connections: prefiere connz.num_connections; si connz no parsea, cae a varz.connections para no perder la serie.
  • RAFT leader en standalone: en un nats-server sin clúster, el objeto cluster puede faltar o leader venir vacío; en ese caso nats_jetstream_raft_leader sale 0 salvo que cluster.leader == node. Es esperado: en standalone no hay quorum RAFT real.
  • kv_bucket_msgs solo se emite para streams cuyo nombre empieza por KV_, recortando el prefijo (stream KV_UNIBUS_users → bucket UNIBUS_users).
  • nats_server_start_seconds es el epoch Unix del campo start (RFC3339): sirve como proxy de reinicios (un cambio de valor = el server reinició). Si el campo no parsea como fecha válida, la serie se omite en lugar de abortar.