From 2c41b80f975523e55ac05321c66409119b3f2762 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Sun, 7 Jun 2026 20:57:45 +0700 Subject: [PATCH] feat: expose /metrics endpoint and add telemetry ClickHouse credentials --- .env.example | 6 ++ Makefile | 149 +++++++++++++++++++++++++++++++++++ apps/web/nginx.conf | 9 +++ docker-compose.telemetry.yml | 30 +++++++ 4 files changed, 194 insertions(+) create mode 100644 Makefile create mode 100644 docker-compose.telemetry.yml diff --git a/.env.example b/.env.example index 9099563..677317f 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,9 @@ WEB_PORT=5173 API_PORT=3000 DATABASE_URL=postgres://postgres:postgres@localhost:5432/zeavis_edu + +# ── Telemetry / ClickHouse ────────────────────────────────────────── +# These credentials are used by the telemetry Docker Compose stack. +# See telemetry/deploy/.env.example for production overrides. +CLICKHOUSE_USER=telemetry +CLICKHOUSE_PASSWORD=telemetry diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3c6c015 --- /dev/null +++ b/Makefile @@ -0,0 +1,149 @@ +# ============================================================================= +# ZeaVis Edu — Root Makefile +# +# Orchestrates the application stack (web, api, ml) and the telemetry +# metric pipeline (Prometheus → Ingester → Vector → ClickHouse). +# +# Telemetry commands operate on the submodule at telemetry/. +# ============================================================================= + +.PHONY: dev build typecheck +.PHONY: telemetry-up telemetry-down telemetry-build telemetry-logs telemetry-restart telemetry-init-db telemetry-test-metric telemetry-status +.PHONY: up-all down-all + +SHELL := /bin/bash + +# ────────────────────────────────────────────────────────────────────────────── +# Application (Bun / Moon) +# ────────────────────────────────────────────────────────────────────────────── + +dev: + bun run dev + +build: + bun run build + +typecheck: + bun run typecheck + +# ────────────────────────────────────────────────────────────────────────────── +# Telemetry Stack +# +# Docker commands reference the telemetry submodule compose file: +# telemetry/deploy/docker-compose.yml +# +# For local development, append the port override: +# make telemetry-up-local +# +# The telmetry compose file is inside the submodule so paths (volumes, +# build context) are relative to telemetry/ — but we run docker compose +# from the project root using -f. +# ────────────────────────────────────────────────────────────────────────────── + +TELEMETRY_COMPOSE := telemetry/deploy/docker-compose.yml +TELEMETRY_LOCAL := telemetry/deploy/docker-compose.local.yml +TELEMETRY_ZEAVIS := docker-compose.telemetry.yml + +# Start all telemetry services +telemetry-up: + @echo ">> Starting Telemetry stack..." + CLICKHOUSE_USER=$${CLICKHOUSE_USER:-telemetry} \ + CLICKHOUSE_PASSWORD=$${CLICKHOUSE_PASSWORD:-telemetry} \ + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_ZEAVIS) up -d + @echo ">> Telemetry stack started. Use 'make telemetry-logs' to view output." + +# Start telemetry services with local port overrides (no Tailscale) +telemetry-up-local: + @echo ">> Starting Telemetry stack (local mode)..." + CLICKHOUSE_USER=$${CLICKHOUSE_USER:-telemetry} \ + CLICKHOUSE_PASSWORD=$${CLICKHOUSE_PASSWORD:-telemetry} \ + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_LOCAL) -f $(TELEMETRY_ZEAVIS) up -d + @echo ">> Telemetry stack started in local mode." + +# Stop all telemetry services +telemetry-down: + @echo ">> Stopping Telemetry stack..." + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_ZEAVIS) down + @echo ">> Telemetry stack stopped." + +# Build telemetry components (metric-ingester + telemetry-ui) +# Runs inside the telemetry submodule using its own Makefile. +telemetry-build: + @echo ">> Building Telemetry components..." + $(MAKE) -C telemetry build + @echo ">> Telemetry components built." + +# Tail telemetry logs (optionally filter by service: s=) +telemetry-logs: +ifdef s + CLICKHOUSE_USER=$${CLICKHOUSE_USER:-telemetry} \ + CLICKHOUSE_PASSWORD=$${CLICKHOUSE_PASSWORD:-telemetry} \ + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_ZEAVIS) logs -f $(s) +else + CLICKHOUSE_USER=$${CLICKHOUSE_USER:-telemetry} \ + CLICKHOUSE_PASSWORD=$${CLICKHOUSE_PASSWORD:-telemetry} \ + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_ZEAVIS) logs -f +endif + +# Restart a single telemetry service +telemetry-restart: +ifdef s + @echo ">> Restarting service: $(s)..." + CLICKHOUSE_USER=$${CLICKHOUSE_USER:-telemetry} \ + CLICKHOUSE_PASSWORD=$${CLICKHOUSE_PASSWORD:-telemetry} \ + docker compose -f $(TELEMETRY_COMPOSE) -f $(TELEMETRY_ZEAVIS) restart $(s) + @echo ">> Service $(s) restarted." +else + @echo "Usage: make telemetry-restart s=" + @echo "Services: prometheus metric-ingester vector clickhouse query-proxy telemetry-ui" + @exit 1 +endif + +# Initialize ClickHouse schema +telemetry-init-db: + @echo ">> Initializing ClickHouse schema..." + cd telemetry/clickhouse && DOCKER_CONTAINER=telemetry-clickhouse bash init.sh + @echo ">> Schema initialized." + +# Send a test metric through the pipeline +telemetry-test-metric: + @echo ">> Sending test metric to Vector on port 9001..." + curl -X POST http://localhost:9001/metrics \ + -H "Content-Type: application/json" \ + -d '{"metric_name":"test_zeavis","value":1.0,"timestamp":"$(shell date -u +%Y-%m-%dT%H:%M:%SZ)","labels":{"service":"zeavis-edu"},"env":"dev","region":"local"}' + @echo "" + @echo ">> Metric sent. Check telemetry-logs to verify ingestion." + +# Show service status (health check overview) +telemetry-status: + @echo ">> Telemetry stack status:" + @echo "" + @echo "--- Prometheus ---" + -curl -s --max-time 3 http://localhost:9090/-/healthy && echo " healthy" || echo " unhealthy" + @echo "" + @echo "--- Metric Ingester ---" + -curl -s --max-time 3 http://localhost:9091/health || echo " unhealthy" + @echo "" + @echo "--- Vector ---" + -curl -s --max-time 3 http://localhost:9001/health || echo " unhealthy" + @echo "" + @echo "--- ClickHouse ---" + -curl -s --max-time 3 http://localhost:8123/ping && echo " healthy" || echo " unhealthy" + @echo "" + @echo "--- Query Proxy ---" + -curl -s --max-time 3 http://localhost:9092/health || echo " unhealthy" + @echo "" + @echo "--- Telemetry UI ---" + -curl -s --max-time 3 -o /dev/null -w "%{http_code}" http://localhost:8181/ && echo " ok" || echo " unhealthy" + +# ────────────────────────────────────────────────────────────────────────────── +# Combined +# ────────────────────────────────────────────────────────────────────────────── + +# Start everything (app + telemetry) +up-all: telemetry-up + bun run dev + +# Stop everything +down-all: telemetry-down + @echo ">> All services stopped." diff --git a/apps/web/nginx.conf b/apps/web/nginx.conf index d15888c..11bce60 100644 --- a/apps/web/nginx.conf +++ b/apps/web/nginx.conf @@ -12,6 +12,15 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } + # Expose API metrics through the web endpoint (Prometheus scrape target) + location /metrics { + proxy_pass http://zeavis-api:3000/metrics; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + location / { try_files $uri $uri/ /index.html; } diff --git a/docker-compose.telemetry.yml b/docker-compose.telemetry.yml new file mode 100644 index 0000000..bbeb679 --- /dev/null +++ b/docker-compose.telemetry.yml @@ -0,0 +1,30 @@ +# ============================================================================= +# ZeaVis Edu — Telemetry Stack Integration +# +# Extends the Telemetry submodule docker-compose to share the app network so +# Prometheus can scrape the ZeaVis Edu services (web, api, ml). +# +# Usage (from project root): +# docker compose -f telemetry/deploy/docker-compose.yml \ +# -f docker-compose.telemetry.yml up -d +# ============================================================================= + +networks: + app-shared-net: + external: true + name: app-shared-net + telemetry-net: + external: true + name: telemetry-net + +services: + # ── Telemetry services join the app network for scraping ───────────── + prometheus: + networks: + - default + - app-shared-net + + # ── ZeaVis Edu app services join the telemetry network ─────────────── + # These are defined here so Prometheus can reach them without scope + # conflicts. When deployed via the root docker-compose.yml, they already + # share both networks — this override ensures local dev works too.