# Observability (ClickStack / HyperDX) — ohmu **Loodud 2026-09-25.** ClickStack = HyperDX UI + (väline) ClickHouse + kaasas olev OTel-kollektor. Kogu grupp on **always-on** (ei ole enam `experimental`). ## Ligipääs - UI: **http://100.87.1.24:8124/clickstack/search** (läbi `clickstack-proxy`) - UI otse: http://100.87.1.24:18080 - Kasutaja: `admin@odamus.com` / `Dev_clickhouse_2026!` - ClickHouse (väline, `clickhouse` konteiner): HTTP 8125, native 9004 (Tailscale-only) ## Arhitektuur (andmevoog) ``` node-exporter ─┐ cadvisor ──────┼─► otel-collector (scrape 60s) ─► clickstack:4317 (kaasas kollektor) ─► ClickHouse (default.otel_*) llama.cpp ─────┘ (main_ai_network) (opampsupervisor) ``` - `otel-collector` (contrib) skrape'ib node-exporter, cadvisor ja **llama.cpp** (`host.docker.internal:8070/metrics`). - Kaasas olev kollektor (clickstack konteineris) võtab configu API-lt (opamp, port 4320) ja kirjutab ClickHouse'i `otel_*` tabelitesse. - **Kriitiline:** `clickstack-entry.sh` peab käivitama `/otel-entrypoint.sh /usr/local/bin/opampsupervisor` — muidu OTLP andmed ei püsi. ## ClickHouse tabelid (default) `otel_logs`, `otel_traces`, `otel_metrics_gauge|sum|histogram|exponential_histogram|summary` + rollupid. Skeem luuakse automaatselt schema-seed'iga (goose). ## Konfiguratsioon | Fail | Sisu | |---|---| | `dev/docker-compose.yml` | `clickstack`, `clickstack-proxy`, `node-exporter`, `cadvisor`, `otel-collector` (always-on) | | `dev/config/otel-collector/config.yaml` | prometheus receiver (node/cadvisor/llamacpp) + regexp-filter + OTLP eksport | | `dev/clickstack-entry.sh` | mongod + **OTel-kollektor** + HyperDX app | | `dev/.env` | `HYPERDX_INGEST_KEY` (gitignore'itud) — kollektori OTLP auth | ### ClickStack env (olulised) - `CLICKHOUSE_ENDPOINT=tcp://clickhouse:9000?dial_timeout=10s` - `CLICKHOUSE_USER=default`, `CLICKHOUSE_PASSWORD=dev_clickhouse_2026` - `HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=default` - `DEFAULT_CONNECTIONS=[{"name":"Local ClickHouse","host":"http://clickhouse:8123","username":"default","password":"dev_clickhouse_2026"}]` ## ClickHouse ühendus (HyperDX Connections) — ÕIGE seadistus Ühendusel peavad olema **eraldi väljad** `username`/`password` ja `host` **ilma userinfo'ta** (`http://clickhouse:8123`). Siis lisab CH-proxy `X-ClickHouse-User`/`Key` päised. > ❗ **Local mode peab olema VÄLJAS:** `NEXT_PUBLIC_IS_LOCAL_MODE=false`. > Koos välise (mitte-image'sisese) ClickHouse'iga põhjustab `true` selle, et brauser > kasutab lokaalset ühendust (sessionStorage/`__ENV.js`) ja saadab ise `Authorization`/ > `user=` → proxy lisab omakorda `X-ClickHouse-*` → **Code 516** või `UNKNOWN_USER`. > Väärtus injekteeritakse **runtime'is** `public/__ENV.js` kaudu → piisab > `docker compose up -d --force-recreate clickstack` (kontroll: `cat .../public/__ENV.js`). > ❗ Varasem soovitus hoida `username`/`password` tühjad ja panna tunnused > host-URL-i (`http://default:parool@clickhouse:8123`) **ei tööta**: `http-proxy-middleware` > ei edasta host-URL-i parooli → CH saab kasutaja `default` tühja parooliga → > „Authentication failed: password is incorrect". (Kinnitatud `tcpdump -i any 'tcp port 8123'`-ga.) Mongo otsene parandus: ```javascript db.connections.updateOne({_id: ObjectId("")}, {$set:{host:"http://clickhouse:8123", username:"default", password:"dev_clickhouse_2026"}}); ``` > Pärast otsest mongo-muudatust **taaskäivita `clickstack`** (muidu jääb vahemällu): > `docker restart clickstack`. **Code 516 hoiatus:** kui ühendusel on `username` JA päring sisaldab `user=` query-param, tuleb `Code: 516 ... X-ClickHouse HTTP headers and authentication via parameters simultaneously`. Seetõttu ei tohi ühendust anda browseri CH-kliendile koos username'iga; HyperDX metadataklient (`W({queryTimeout})`) ehitab kliendi **ilma** username'ita → OK. ## Logide kogumine (filelog) `otel-collector` loeb Dockeri konteineriloge: - `receivers.filelog`: `include: /var/lib/docker/containers/*/*-json.log`, `container` parser, `start_at: end` - `service.pipelines.logs`: `[filelog] → [memory_limiter, batch] → [otlp]` - Compose: `otel-collector` vajab **mounti** `/var/lib/docker/containers:/var/lib/docker/containers:ro` **ja `user: "0:0"`** (mitte-root kasutaja → „open .: permission denied"). - Kontroll: `SELECT count(), max(Timestamp) FROM default.otel_logs`. ## Metrikad (praegu) - **Host:** RAM (available/total), swap, load, CPU, failisüsteem, võrk (node-exporter). - **Konteinerid:** CPU, mälu (working set/usage), võrk (cadvisor). - **Mudel:** llama.cpp — prompt/ predicted tokens, requests_processing, kv_cache (`--metrics`). ## Dashboardid (retseptid) HyperDX UI-s: **Dashboards → New dashboard → Add tile**. Kasuta allolevaid metrikaid (Metrics source) või "SQL" diagrammi. Ajatelje jaoks sobib `TimeUnix`. | Paneel | Mõõdik / SQL | |---|---| | RAM vaba | `node_memory_MemAvailable_bytes` (gauge) | | Swap vaba | `node_memory_SwapFree_bytes` (gauge) | | Load | `node_load1` (gauge) | | Konteineri mälu | `container_memory_working_set_bytes` (group: `Attributes['name']`) | | Konteineri CPU | `container_cpu_usage_seconds_total` (rate) | | **Llama tokeneid/s** | `rate(llamacpp:tokens_predicted_total)` või pika aja trend | | **Llama päringud** | `llamacpp:requests_processing` (gauge), `llamacpp:tokens_predicted_total` (sum) | | **Llama KV-cache** | `llamacpp:kv_cache_usage_ratio` (gauge) | | **Teenus üleval** | `ohmu_service_up` (group: `Attributes['service']`) | | **Restardid** | `ohmu_container_restarts` (group: `Attributes['name']`) | Näidis-SQL (ClickHouse): ```sql -- Teenuste seis viimase 10 min jooksul SELECT toStartOfMinute(TimeUnix) AS t, Attributes['service'] AS service, avg(Value) AS up FROM default.otel_metrics_gauge WHERE MetricName = 'ohmu_service_up' AND TimeUnix > now() - INTERVAL 10 MINUTE GROUP BY t, service ORDER BY t; ``` ## Teadaolevad UI-nõksud ### Metrika-paneeli `select` skeem (HyperDX 2.37) Metrika-diagramm ja alert nõuavad, et `select[]` elemendil oleks: `{metricName, metricType, aggFn, isDelta, filters: [], valueExpression: "Value"}`, kus `metricType` ∈ `gauge|sum|histogram|summary|exponential histogram`. Vana `aggCondition`-ainult kuju annab **`no query support for metric type=undefined`**. `valueExpression` on vajalik, sest alerti config lisab `variables` → macro-töötlus loeb `select[].valueExpression` (puudumisel `TypeError: Cannot read properties of undefined (reading 'length')`). `metricType` määra ClickHouse'i tabeli järgi (`otel_metrics_gauge|sum|histogram|...`): nt `llamacpp:tokens_predicted_total` → `sum`, `node_load1`/`ohmu_service_up` → `gauge`. ### Alert nõuab number/line/stacked bar paneeli Alert **ei toeta `table`-paneeli** (`Unsupported alert source: tile`). Kasuta `number`/`line`/`stacked bar` paneeli. Pärast alerti/paneeli otsest mongo-muudatust **taaskäivita `clickstack`** (vahemälu). ### Chart Explorer: `Syntax error ... toString()` (tühi valueExpression + count) Vaikimisi Chart Explorer'i seeria on `{aggFn:"count", valueExpression:""}`. HyperDX 2.37 genereerib y-telje min/max päringu kujul `toFloat64OrDefault(toString())` (tühi argument) → `Code: 62 SYNTAX_ERROR ... failed at position 58 (>=)`. **Lahendus:** pane seeria **Value** väljale `1` (või mõni veerg) → `count()` + `toString(1)` on korrektne: ```sql SELECT count() FROM default.otel_logs; -- seeria ise töötab SELECT quantileIf(0.01)(toFloat64OrDefault(toString(1)), 1>=0 AND ...) AS "min", MAX(toFloat64OrDefault(toString(1))) AS "max" FROM default.otel_logs; -- OK ``` UI-s: Chart Explorer → seeria → **Value** = `1`; alternatiivselt kasuta `table`-kuva (min/max päringut ei tehta). See on upstream HyperDX nõks, mitte andmeviga. ### Heatmap: „Value expression is required for heatmap charts" Chart Explorer → Heatmap nõuab, et seeria **Value expression** oleks täidetud (HyperDX valideerib `series[0].valueExpression`). See on UI-konfiguratsioon, mitte andmeviga. - **Metrics** source: vali metrika (nt `node_load1`) ja sisesta **Value** väljale `Value` (või `avg(Value)`), lisa filtrisse `MetricName`. - **Logs** source: Value väljale `count()`; "Group by" nt `ServiceName` või `SeverityText`. - Kui metrika valimine ei täida Value välja automaatselt, trüki see käsitsi. ### Metrics source peab sisaldama `metricTables.exponentialHistogram` Vaikimisi bootstrap võib selle puudumisel metrikate valija katki teha. Kontroll: ```bash docker exec clickstack mongo --quiet hyperdx --eval \ 'printjson(db.sources.findOne({kind:"metric"}).metricTables)' # vajadusel: db.sources.updateOne({kind:"metric"},{$set:{"metricTables.exponentialHistogram":"otel_metrics_exponential_histogram"}}) ``` ## Näidis-dashboardid Loodud 2026-09-25 skriptiga **`~/scripts/create_hyperdx_dashboards.py`**: - **„Ohmu — süsteem (host)"** — RAM vaba, swap vaba, load1, konteinerite mälu (host metrikad) - **„Ohmu — mudelid (llama.cpp)"** — genereeritud/prompt-tokenid, aktiivsed päringud, KV-cache - **„Ohmu — teenused ja konteinerid"** — `ohmu_service_up`, `ohmu_container_restarts` Kordamine: `python3 ~/scripts/create_hyperdx_dashboards.py` (`--delete-tests` koristab testid). **API ligipääs:** HyperDX väline API v2 on **`http://:8000/api/v2`** (hostilt konteineri IP kaudu; `clickstack-proxy` ribab `/api` prefiksi, seega `:18080` kaudu ei tööta). Access key: `docker exec clickstack mongo --quiet hyperdx --eval 'print(db.users.findOne({email:"admin@odamus.com"}).accessKey)'`. **Tile-vorming (API):** ```json {"name":"paneel","x":0,"y":0,"w":6,"h":6,"config":{ "displayType":"line","sourceId":"", "select":[{"valueExpression":"Value","aggFn":"avg","where":"MetricName:\"node_load1\""}], "groupBy":"name"}} ``` ## Alertid (Telegram) Rakendatud: **HyperDX webhook → `alert-relay` → Telegram**. - **`alert-relay`** konteiner (`dev/config/alert-relay/alert_relay.py`, `python:3.12-slim`, port 9099): võtab vastu HyperDX „generic" webhook POST-id ja saadab Telegrami. Token `dev/.env`-st (`TELEGRAM_BOT_TOKEN`), chat `5036685258`. - **Webhook:** `Telegram (ohmu)` → `http://alert-relay:9099/` (id `6ab760240c9282a5b0fde124`). - **Alert:** „Teenus maas (ohmu_service_up)" → dashboardi paneel „Teenused üleval", `thresholdType=below`, `threshold=1`, `interval=5m`, kanal webhook (id `6ab7603c0c9282a5b0fde12d`). **Oluline API-piirang:** väline API v2 (`POST /api/v2/alerts`) toetab ainult `source: "tile"` või `"saved_search"` — **`inline` alert on ainult sisemise API jaoks**. Paneeli-alert viitab: `{source:"tile", tileId, dashboardId}`; kanal: `{"type":"webhook","webhookId":"..."}`. **Testimine:** ```bash # relay otse (hostilt pole 9099 avaldatud; kasuta konteinerit võrgus): docker run --rm --network main_ai_network curlimages/curl:latest -s \ -X POST http://alert-relay:9099/ -d '{"name":"test","state":"ALERT"}' ``` Tüüpilised täiendavad alertid (sama muster: tile + webhook + below/above): - `node_memory_MemAvailable_bytes` < X (RAM otsas) - `ohmu_container_restarts` > 0 (restart-loop) - `llamacpp:kv_cache_usage_ratio` > 0.9 ## Seotud - Vahejuhtumite audit: `../LOEMIND_seisevad_konteinerid.md` - Serveri mudelid: `~/servers/LOEMIND/llama-server.md`