From 98fafcd93c8c6b67f451269ec3c01e060aa41c4c Mon Sep 17 00:00:00 2001 From: zwitschi Date: Mon, 10 Aug 2026 16:53:52 +0200 Subject: [PATCH] docs: adding more details for monitoring and operations --- docs/MONITORING.md | 7 ++ docs/STREAMING.md | 2 +- .../monitoring/prometheus_curl.md | 71 +++++++++++ .../monitoring/prometheus_curl_win.md | 96 ++++++++++++++ docs/operations/cloudflare-pages-setup.md | 2 + docs/operations/gitea-cloudflare.pages.md | 118 ++++++++++++++++++ 6 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 docs/infrastructure/monitoring/prometheus_curl.md create mode 100644 docs/infrastructure/monitoring/prometheus_curl_win.md create mode 100644 docs/operations/gitea-cloudflare.pages.md diff --git a/docs/MONITORING.md b/docs/MONITORING.md index 3af392b..67945c5 100644 --- a/docs/MONITORING.md +++ b/docs/MONITORING.md @@ -52,6 +52,13 @@ Config: `monitoring/prometheus/prometheus.yml` (15s scrape interval) - **Linear Void app**: `monitoring/grafana/dashboard.json` — clients, messages, moderation, Redis, sessions, scrape health - **Prometheus ops**: `monitoring/grafana/dashboards/dashboard.json` — TSDB, CPU/memory, WAL, compactions, query latency +## Metrics checking + +See detailed scripts for querying Prometheus scrape targets: + +- [Linux/macOS](./infrastructure/monitoring/prometheus_curl.md) +- [Windows](./infrastructure/monitoring/prometheus_curl_win.md) + ## Key Metrics - `linearvoid_chat_connected_clients` — active WebSocket connections diff --git a/docs/STREAMING.md b/docs/STREAMING.md index e44f88c..c408ed6 100644 --- a/docs/STREAMING.md +++ b/docs/STREAMING.md @@ -5,7 +5,7 @@ This document is the operational contract for Linear Void video ingest, playout, ## Production flow ```mermaid -flowchart LR +flowchart TD A["Normalized MP4 assets"] --> B["Playlist and schedule"] B --> C["Playout service and FFmpeg"] C --> D["Local HLS staging"] diff --git a/docs/infrastructure/monitoring/prometheus_curl.md b/docs/infrastructure/monitoring/prometheus_curl.md new file mode 100644 index 0000000..c22244c --- /dev/null +++ b/docs/infrastructure/monitoring/prometheus_curl.md @@ -0,0 +1,71 @@ +# Prometheus scrape target metric names + +Here are ready‑to‑run **cURL** commands you can use to query each Prometheus scrape target and list the metric names they expose. +The Prometheus HTTP API endpoint `http://localhost:9090/api/v1/label/__name__/values` returns all metric names currently known for the target’s job/instance. + +--- + +## 1. Chat (`http://chat:3000/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="chat",instance="chat:3000"}' | jq . +``` + +## 2. NGINX exporter (`http://nginx-exporter:9113/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="nginx",instance="nginx-exporter:9113"}' | jq . +``` + +## 3. Node exporter (`http://node-exporter:9100/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="node",instance="node-exporter:9100"}' | jq . +``` + +## 4. Playout (`http://playout:8081/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="playout",instance="playout:8081"}' | jq . +``` + +## 5. Postgres exporter (`http://postgres-exporter:9187/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="postgres",instance="postgres-exporter:9187"}' | jq . +``` + +## 6. Prometheus itself (`http://prometheus:9090/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="prometheus",instance="prometheus:9090"}' | jq . +``` + +## 7. Redis exporter (`http://redis-exporter:9121/metrics`) + +```bash +curl -s 'http://localhost:9090/api/v1/label/__name__/values?match[]={job="redis",instance="redis-exporter:9121"}' | jq . +``` + +--- + +### How it works + +- `http://localhost:9090` – address of your Prometheus server. +- `/api/v1/label/__name__/values` – API call that lists _all_ metric names (`__name__` label) known to Prometheus. +- `match[]` – a selector that restricts the result to the specific `job` and `instance` you care about. +- `-s` – silent mode (no progress meter). +- `| jq .` – pretty‑prints the JSON response (optional but handy). + +Running any of these commands will output a JSON array like: + +```json +[ + "up", + "process_cpu_seconds_total", + "http_requests_total", + ... +] +``` + +which is the full set of metrics currently being scraped from that target. Adjust the Prometheus host/port if it differs from `http://localhost:9090`. diff --git a/docs/infrastructure/monitoring/prometheus_curl_win.md b/docs/infrastructure/monitoring/prometheus_curl_win.md new file mode 100644 index 0000000..07ee17a --- /dev/null +++ b/docs/infrastructure/monitoring/prometheus_curl_win.md @@ -0,0 +1,96 @@ +# Prometheus scrape target metric names (Windows) + +Below are **cURL** one‑liners you can run from a Windows command prompt (or PowerShell) that query the Prometheus HTTP API and print the raw JSON list of metric names for each target. +Since **jq** isn’t installed, the commands simply echo the JSON response; you can pipe it to `findstr` or PowerShell’s `ConvertFrom‑Json` if you want a prettier view. + +--- + +## 1. Chat (`http://chat:3000/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"chat\",instance=\"chat:3000\"}" +``` + +## 2. NGINX exporter (`http://nginx-exporter:9113/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"nginx\",instance=\"nginx-exporter:9113\"}" +``` + +## 3. Node exporter (`http://node-exporter:9100/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"node\",instance=\"node-exporter:9100\"}" +``` + +## 4. Playout (`http://playout:8081/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"playout\",instance=\"playout:8081\"}" +``` + +## 5. Postgres exporter (`http://postgres-exporter:9187/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"postgres\",instance=\"postgres-exporter:9187\"}" +``` + +## 6. Prometheus itself (`http://prometheus:9090/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"prometheus\",instance=\"prometheus:9090\"}" +``` + +## 7. Redis exporter (`http://redis-exporter:9121/metrics`) + +```cmd +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=\"redis\",instance=\"redis-exporter:9121\"}" +``` + +--- + +### Making the output a bit more readable (optional) + +If you have **PowerShell** (available on Windows 10/11), you can format the JSON nicely: + +```powershell +curl "http://localhost:9090/api/v1/label/__name__/values?match[]={job=`"chat`",instance=`"chat:3000`"}" | + ConvertFrom-Json | + Select-Object -ExpandProperty data | + Sort-Object +``` + +Replace the URL part with the one for the target you’re interested in. The pipeline: + +1. Calls `curl` (the built‑in alias for `Invoke-WebRequest` in PowerShell). +2. `ConvertFrom-Json` parses the JSON. +3. `Select-Object -ExpandProperty data` extracts the array of metric names. +4. `Sort-Object` alphabetizes them. + +You can similarly pipe the output to `findstr /i "http_requests_total"` to search for a particular metric name without any extra tools. + +--- + +### Quick checklist + +| Item | What to adjust | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| **Prometheus address** | If your Prometheus container isn’t bound to `localhost:9090`, replace `localhost:9090` with the appropriate host/port (e.g., `127.0.0.1:9090`). | +| **Target job/instance** | The `job` and `instance` values must match the labels shown in your UI (they’re case‑sensitive). | +| **PowerShell vs CMD** | The raw `curl` commands work in both CMD and PowerShell; the PowerShell‑only pretty‑print uses `ConvertFrom‑Json`. | + +Run the command for any target and you’ll receive a JSON payload like: + +```json +{ + "status": "success", + "data": [ + "up", + "process_cpu_seconds_total", + "http_requests_total", + "... more metrics ..." + ] +} +``` + +That array (`data`) is the complete list of metric names currently scraped from the specified endpoint. diff --git a/docs/operations/cloudflare-pages-setup.md b/docs/operations/cloudflare-pages-setup.md index 262221a..996a93d 100644 --- a/docs/operations/cloudflare-pages-setup.md +++ b/docs/operations/cloudflare-pages-setup.md @@ -46,6 +46,8 @@ Connect the Gitea repository directly in Cloudflare Pages: Cloudflare handles builds and deploys automatically on push. +> **Naming:** If `linearvoid` is already used by the Worker service, name the Pages project `linearvoid-site` (or similar). Workers and Pages share a namespace. + ### Option B: Direct Upload via Gitea Actions Use `.gitea/workflows/pages-deploy.yml` to build in Gitea Actions and upload via the Cloudflare API. diff --git a/docs/operations/gitea-cloudflare.pages.md b/docs/operations/gitea-cloudflare.pages.md new file mode 100644 index 0000000..58a2e20 --- /dev/null +++ b/docs/operations/gitea-cloudflare.pages.md @@ -0,0 +1,118 @@ +# Gitea to Cloudflare Pages — Linear Void + +## Goal + +Deploy the Linear Void frontend (Vite + TypeScript SPA) from Gitea to Cloudflare Pages using Gitea Actions. + +## Prerequisites + +> **Important:** The Pages project must exist before the API deploy call works. You'll get error 8000007 ("Project not found") if you skip this step. + +1. **Cloudflare Pages project** created first: + - Dashboard → Workers & Pages → Create → Pages → Direct Upload + - Name it `linearvoid` (or a different name if `linearvoid` is already taken by a Worker — see note below) + - See [Cloudflare Pages Setup](./cloudflare-pages-setup.md) for full details. +2. **Project name**: note the exact name (e.g., `linearvoid`). +3. **API token** with Pages permissions: + - Create at + - Permission: `Account → Cloudflare Pages → Edit` + - Store in Gitea → Settings → Secrets as `CLOUDFLARE_API_TOKEN` +4. **Account ID** from Cloudflare dashboard overview → store as `CLOUDFLARE_ACCOUNT_ID` + +> **Naming conflict:** If a Worker already exists with the name `linearvoid`, the Pages project must use a different name (e.g., `linearvoid-site`). Update the `projectName` in the workflow accordingly. Workers and Pages share a namespace under "Workers & Pages". + +## Project-specific values + +| Setting | Value | +| ------------------ | ---------------------------------------------------------- | +| Framework | Vite + TypeScript | +| Build command | `cd frontend && npm install && npm run build` | +| Output directory | `frontend/dist` | +| Node version | 20 | +| Multi-page entries | `index.html`, `admin/index.html`, `admin/login/index.html` | + +## Gitea Actions workflow + +Create `.gitea/workflows/pages-deploy.yml`: + +```yaml +name: Deploy to Cloudflare Pages + +on: + push: + branches: ["main"] + workflow_dispatch: {} + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: cd frontend && npm ci + + - name: Build + run: cd frontend && npm run build + + - name: Deploy to Cloudflare Pages + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: linearvoid + directory: frontend/dist + gitHubToken: ${{ secrets.GITEA_TOKEN }} +``` + +If the `cloudflare/pages-action@v1` action is unavailable from Gitea, use the direct API approach: + +```yaml +- name: Create deployment artifact + run: tar -czf site.tgz -C frontend/dist . + +- name: Deploy to Cloudflare Pages + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + run: | + curl -sS -X POST \ + "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/linearvoid/deployments" \ + -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @site.tgz +``` + +## Secrets to add in Gitea + +| Secret | Value | +| ----------------------- | ------------------------------------ | +| `CLOUDFLARE_API_TOKEN` | API token with Pages:Edit permission | +| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID from dashboard | + +## Verify deployment + +1. Push to `main` or trigger manually from Gitea Actions. +2. Check **Gitea Actions** → job logs for the deploy step. +3. Check **Cloudflare Pages** → Deployments for the new deployment. +4. Visit the `.pages.dev` preview URL, then promote to `linearvoid.tv` when ready. + +## Notes + +- The existing `ci.yml` already builds the frontend; the Pages deploy workflow is additive and independent. +- Multi-page SPA (`vite.config.ts`) produces three entry points — Cloudflare Pages serves them correctly. +- For SPA fallback routing, add a `frontend/public/_redirects` file with `/* /index.html 200` before building. +- If deployments fail with 403, verify the API token has `Account → Cloudflare Pages → Edit` permission. +- If you get error **8000007** ("Project not found"), the Pages project hasn't been created yet. Create it via the Cloudflare dashboard (Workers & Pages → Create → Pages → Direct Upload) first, then re-run. +- If `linearvoid` is already taken by a Worker, use a different project name like `linearvoid-site` and update the `projectName` and `PROJECT_NAME` values in the workflow. + +## Related resources + +- Cloudflare Workers dashboard: `https://dash.cloudflare.com/{accountId}/workers/services/view/linearvoid/production/settings` — for managing the `infrastructure/cloudflare/worker.js` deployment +- Cloudflare Pages project: `https://dash.cloudflare.com/{accountId}/pages/view/linearvoid` — deployment history and custom domain settings