Skip to content

feat(observability): add node-exporter, cAdvisor, redis_exporter, scrape Qdrant + self-monitor the observability stack #5366

Description

@JSONbored

Part of #5365.

Context: The self-host stack currently has zero visibility into host-level resource usage, per-container resource usage, or Redis — despite Redis being an always-on, required backend. Meanwhile two "free wins" exist: Qdrant already exposes a native Prometheus /metrics endpoint (:6333/metrics) that's simply never scraped, and Prometheus/Alertmanager/Loki/Tempo/Grafana all expose their own native /metrics too, unscraped — so the observability stack itself is currently unmonitored.

Requirements:

  1. Add node-exporter (prom/node-exporter, official image) — host CPU/memory/disk/network. Standard --profile observability-gated service, mirroring the existing gpu-exporter/postgres-exporter wiring conventions in docker-compose.yml (health-gated, resource-limited via deploy.resources.limits.memory with an .env.example-documented override var, per the pattern this repo already uses for every other exporter).
  2. Add cadvisor (gcr.io/cadvisor/cadvisor, official image) — per-container CPU/memory/network/disk-io. Needs read-only mounts of /var/run/docker.sock, /sys, /var/lib/docker — evaluate whether this should go through the existing isolated docker-proxy network (the same isolation reasoning already documented for Promtail's container-discovery access) rather than mounting the raw socket directly.
  3. Add redis_exporter (oliver006/redis_exporter, official image) — Redis has no native Prometheus endpoint; this is the standard sidecar.
  4. Add a qdrant scrape target to prometheus/prometheus.yml (qdrant:6333, path /metrics) — no new service needed, already confirmed live.
  5. Add self-monitoring scrape targets for prometheus:9090, alertmanager:9093, loki:3100, tempo:3200, grafana:3000 (/metrics on each, confirmed live against edge-nl-01) — mirror the existing "absent target just shows down, no alert fires" comment convention already used for GPU/backup targets, since not every self-hoster runs every one of these (e.g., Qdrant is --profile qdrant-gated).
  6. Enable the OTEL collector's internal telemetry (service.telemetry.metrics.address: 0.0.0.0:8888 in otel/otel-collector-config.yml) and add a matching scrape target — currently only logs.level: warn is configured, so the collector's own health/dropped-span/dropped-metric counters are invisible.
  7. Build a new Grafana dashboard (e.g. grafana/dashboards/infra-health.json) visualizing all of the above: host CPU/mem/disk/network, per-container resource usage (top-N by CPU/memory), Redis (connected clients, memory, ops/sec, hit ratio), Qdrant (collections, vector count, per-collection breakdown from the metrics already confirmed available), and a "stack self-health" row (Prometheus/Alertmanager/Loki/Tempo/Grafana/OTEL-collector all show as scraped/up). Add it to resource-hub.json's dashboard catalog.
  8. Add deploy.resources.limits.memory for all 3 new services, extend test/unit/selfhost-compose-resource-limits.test.ts and .env.example to match the established pattern.
  9. Extend node scripts/validate-observability-configs.mjs-covered files as needed; add/extend dashboard tests mirroring test/unit/selfhost-grafana-dashboard.test.ts's conventions (dangling-metric-ref checks, panel-id uniqueness, etc.).

Deliverables:

  • 3 new docker-compose.yml services (node-exporter, cadvisor, redis_exporter), each --profile observability-gated, resource-limited, documented in .env.example.
  • Updated prometheus/prometheus.yml with 6 new/updated scrape targets (qdrant, prometheus, alertmanager, loki, tempo, grafana) plus the otel-collector self-telemetry target.
  • Updated otel/otel-collector-config.yml enabling internal telemetry.
  • New grafana/dashboards/infra-health.json (or equivalent), linked from resource-hub.json.
  • Full local-gate-passing test coverage for every change above.

Expected outcomes: A self-hoster can see, from Grafana alone: whether the host machine itself is under memory/CPU/disk pressure; which container is the actual resource hog when something looks off; Redis health without shelling in; Qdrant collection/vector growth over time; and whether the observability stack itself (Prometheus/Loki/Tempo/Grafana/Alertmanager/OTEL collector) is healthy and actually ingesting data, not silently broken.

Links/resources:

  • Existing precedent to mirror: gpu-exporter/postgres-exporter/backup-exporter service definitions in docker-compose.yml, and grafana/dashboards/gpu-metrics.json as the template for a focused infra dashboard.
  • prom/node-exporter, gcr.io/cadvisor/cadvisor, oliver006/redis_exporter — all official, widely-used images.
  • Qdrant's native metrics confirmed live: curl http://qdrant:6333/metrics returns real Prometheus text (app_info, collections_total, collections_vector_total, etc.) as of 2026-07-12.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions