# Observerbarhet Maskinrommets observerbarhetslag: strukturert logging, request-metrikker, jobbkø-dybde og AI-kostnadsovervåking. ## Strukturert logging Maskinrommet bruker `tracing` med `tracing-subscriber`. Format velges via miljøvariabel: | `LOG_FORMAT` | Resultat | |---|---| | `json` | JSON-linjer (maskinlesbart, egnet for log-aggregering) | | *(annet/utelatt)* | Human-readable (standard for utvikling) | Loggnivå styres via `RUST_LOG` (default: `maskinrommet=info`). ### JSON-format eksempel ```json {"timestamp":"2026-03-18T12:00:00Z","level":"INFO","fields":{"method":"GET","path":"/health","status":200,"duration_ms":1.2},"target":"maskinrommet::metrics","message":"request"} ``` ## Metrikk-endepunkt `GET /metrics` returnerer JSON med tre seksjoner: ### request_latency In-memory per-rute statistikk (nullstilles ved restart): ```json { "uptime_secs": 3600, "total_requests": 1234, "routes": { "/health": { "count": 500, "avg_ms": 1.2, "min_ms": 0.3, "max_ms": 15.0, "p50_ms": 0.8, "p95_ms": 3.5, "p99_ms": 12.0 } } } ``` Percentilene beregnes fra de siste 1000 forespørslene per rute. ### queue_depth Sanntidsstatus fra `job_queue`-tabellen: ```json { "pending": 3, "running": 1, "error": 0, "retry": 1, "completed_last_hour": 42 } ``` ### ai_cost Aggregerte AI-kostnader fra `ai_usage_log` for tre tidsperioder (siste time, 24 timer, 30 dager): ```json { "last_hour": { "requests": 5, "input_tokens": 12000, "output_tokens": 3000, "estimated_cost_usd": 0.08 } } ``` Kostnadsestimatet er basert på konservative gjennomsnittspriser ($3/MTok input, $15/MTok output). ### pg_stats PG-ytelsesstatistikk for kjernetabellene (nodes, edges, node_access): ```json { "tables": [ { "table_name": "nodes", "row_count": 19, "index_scan_count": 50, "seq_scan_count": 10, "index_scan_ratio": 0.83 } ], "indexes": [ { "index_name": "idx_edges_target_type", "table_name": "edges", "scan_count": 25, "size_bytes": 16384 } ], "node_access_count": 4, "cache_hit_ratio": 0.9995 } ``` `index_scan_ratio` bør være >0.95 for tabeller med >1000 rader. `cache_hit_ratio` bør være >0.99 — lavere indikerer at PG trenger mer `shared_buffers`. ## Request-logging middleware Alle HTTP-forespørsler logges med: - `method` — HTTP-metode - `path` — Forespørsels-sti - `status` — HTTP-statuskode - `duration_ms` — Total responstid Forespørsler over 200ms logges med `level=WARN` og tag `slow_request`. ## Slow query logging PG-spørringer som tar over 100ms logges med `level=WARN` og tag `slow_query`. Terskelen er definert i `queries.rs::SLOW_QUERY_THRESHOLD_MS`. Instrumenterte spørringer: - `query_nodes` — søk og filtrering med RLS - `query_graph` — rekursiv CTE graf-traversering med RLS - `recompute_access` — node_access-oppdatering (logges i `pg_writes.rs`) ## pg_stat_statements (valgfritt) For detaljert per-spørring statistikk, aktiver pg_stat_statements: 1. Legg til i docker-compose.yml for postgres: `command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all` 2. Restart postgres-containeren 3. Kjør: `CREATE EXTENSION pg_stat_statements;` 4. Se topp-spørringer: ```sql SELECT query, calls, total_exec_time, mean_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20; ``` ## Arkitektur Metrikker samles i minnet (ingen ekstern avhengighet som Prometheus). Designvalg: - **Enkel:** Ingen nye avhengigheter eller ekstern infrastruktur - **Tilstrekkelig:** Queue depth, AI-kostnad og PG-stats fra PG, latency in-memory - **Utvidbar:** Kan legge til Prometheus-eksport senere ved behov