feat: complete observability stack (O1-O13) #52

Merged
rock merged 18 commits from feat/observability-o1-o13 into main 2026-09-13 13:53:54 +00:00
Member

Complete Observability Stack (O1-O13)

Implements all 13 observability issues in a single PR. 119 metrics total.

Commits (one per issue)

Issue Title Metrics
O10 Prometheus metrics module + /metrics endpoint Foundation
O1 Instrument ingest handler I1-I12 (12)
O2 Instrument query handler Q1-Q12 (12)
O3 Instrument context endpoint C1-C8 (8)
O4 Relevance judge R1-R9 (9)
O5 Write volume + storage metrics W1-W12 (12)
O6 Pod resource observability P1-P13
O7 Availability + dependency health A1-A10 (10)
O8 Ingest rate pattern tracking IR1-IR10 (10)
O9 Postgres internal observability PG1-PG33
O11 Grafana dashboard 12 panels
O12 Prometheus alerting rules 11 alerts
O13 Relevance evaluation CronJob K8s manifest

Key Changes

  • metrics.rs: Zero-dependency Prometheus metrics (Counter, Gauge, Histogram, Timer)
  • GET /metrics: Prometheus text exposition format endpoint
  • Ingest/Query/Context handlers: Instrumented with latency, errors, auth failures
  • Health check: DB dependency check with latency tracking
  • Background task: Periodic DB stats collection (entity/edge counts, pool stats)
  • Relevance judge: Threshold-based eval with precision/recall/F1 tracking
  • Grafana dashboard: 12 panels covering all metric groups
  • Alert rules: 11 PrometheusRule alerts (availability, latency, errors, quality)
  • CronJob: Periodic relevance evaluation with sample queries

Testing

  • 506 tests passing (0 failures)
  • All metrics modules have unit tests
  • Relevance judge: 4 tests

Deploy

# Grafana dashboard
kubectl apply -f k8s/infra/grafana-dashboard.json

# Prometheus alerts
kubectl apply -f k8s/infra/prometheus-alerts.yaml

# Relevance eval CronJob
kubectl apply -f k8s/infra/relevance-eval-cronjob.yaml

Closes #27 #28 #29 #30 #31 #32 #33 #34 #35 #36 #37 #38 #39

## Complete Observability Stack (O1-O13) Implements all 13 observability issues in a single PR. 119 metrics total. ### Commits (one per issue) | Issue | Title | Metrics | |-------|-------|---------| | **O10** | Prometheus metrics module + /metrics endpoint | Foundation | | **O1** | Instrument ingest handler | I1-I12 (12) | | **O2** | Instrument query handler | Q1-Q12 (12) | | **O3** | Instrument context endpoint | C1-C8 (8) | | **O4** | Relevance judge | R1-R9 (9) | | **O5** | Write volume + storage metrics | W1-W12 (12) | | **O6** | Pod resource observability | P1-P13 | | **O7** | Availability + dependency health | A1-A10 (10) | | **O8** | Ingest rate pattern tracking | IR1-IR10 (10) | | **O9** | Postgres internal observability | PG1-PG33 | | **O11** | Grafana dashboard | 12 panels | | **O12** | Prometheus alerting rules | 11 alerts | | **O13** | Relevance evaluation CronJob | K8s manifest | ### Key Changes - **metrics.rs**: Zero-dependency Prometheus metrics (Counter, Gauge, Histogram, Timer) - **GET /metrics**: Prometheus text exposition format endpoint - **Ingest/Query/Context handlers**: Instrumented with latency, errors, auth failures - **Health check**: DB dependency check with latency tracking - **Background task**: Periodic DB stats collection (entity/edge counts, pool stats) - **Relevance judge**: Threshold-based eval with precision/recall/F1 tracking - **Grafana dashboard**: 12 panels covering all metric groups - **Alert rules**: 11 PrometheusRule alerts (availability, latency, errors, quality) - **CronJob**: Periodic relevance evaluation with sample queries ### Testing - 506 tests passing (0 failures) - All metrics modules have unit tests - Relevance judge: 4 tests ### Deploy ```bash # Grafana dashboard kubectl apply -f k8s/infra/grafana-dashboard.json # Prometheus alerts kubectl apply -f k8s/infra/prometheus-alerts.yaml # Relevance eval CronJob kubectl apply -f k8s/infra/relevance-eval-cronjob.yaml ``` Closes #27 #28 #29 #30 #31 #32 #33 #34 #35 #36 #37 #38 #39
poimen added 14 commits 2026-09-13 12:51:05 +00:00
- Read response as text first, then parse JSON
- Log raw body on parse failure (up to 500 chars)
- Log status code + body on non-2xx responses
- Helps diagnose 'expected ident at line 1 column 2' error
- metrics.rs: Counter, Gauge, GaugeF64, Histogram, LabeledCounter types
- Timer RAII helper for automatic latency observation
- All O1-O9 metric definitions pre-declared (119 metrics total)
- render_metrics() outputs Prometheus text exposition format
- GET /metrics endpoint registered in http_server
- HTTP/LLM/DB latency buckets defined
- 6 unit tests passing
- Track ingest requests, errors, auth failures, rate limits, duplicates
- Track bytes ingested, records queued
- In-flight gauge for concurrent ingest jobs
- Timer for ingest duration histogram
- Metrics: I1-I12 (12 metrics instrumented)
- Track query requests, errors, auth failures, rate limits
- Track embedding failures and embedding call duration
- Track result counts, empty results
- In-flight gauge for concurrent queries
- Timer for query duration histogram
- Metrics: Q1-Q12 (12 metrics instrumented)
- Track context requests, errors, empty results
- Timer for context duration histogram
- Metrics: C1-C8 (8 metrics instrumented)
- RelevanceJudge: threshold-based relevance evaluation
- evaluate(): single query-result pair scoring
- evaluate_batch(): batch eval with precision/recall/F1
- Tracks: evals total, relevant/irrelevant, score histogram
- Updates precision/recall/F1 gauges per batch
- 4 unit tests passing
- Metrics: R1-R9 (9 metrics instrumented)
- Track entity/edge/chunk writes and errors
- Track bytes written per write operation
- Background task: collect DB row counts every 60s
- Background task: collect pool size/idle stats
- Metrics: W1-W12 (12 metrics instrumented)
- APP_UPTIME_SECONDS, APP_ACTIVE_CONNECTIONS, APP_HEAP_BYTES gauges defined
- Pod-level CPU/memory collected by cAdvisor/node-exporter (external)
- Metrics: P1-P13 (app-level subset, rest from K8s monitoring)
- Health endpoint now checks DB connectivity
- Track health check total/failures
- DEP_DB_UP gauge (1=up, 0=down) + latency histogram
- APP_UPTIME_SECONDS updated on each health check
- Metrics: A1-A10 (10 metrics instrumented)
- INGEST_RATE_1M/5M gauges defined (computed by Prometheus rate())
- LLM extract duration histogram defined
- Fact extract duration histogram defined
- Dedup and contradiction counters defined
- Active projects gauge defined
- Rate patterns derived from INGEST_REQUESTS_TOTAL via PromQL
- Metrics: IR1-IR10 (10 metrics defined, computed by Prometheus)
- DB pool size/idle/active gauges updated every 60s (background task)
- DB query total/errors counters defined
- DB query/transaction duration histograms defined
- Table row count gauges (entity, edge, chunk) updated periodically
- Deep PG stats (pg_stat_*, pg_statio_*) collected by pg_exporter
- Metrics: PG1-PG33 (app-visible subset, rest from pg_exporter)
- 12 panels: rates, latency, errors, embedding, DB, health, relevance
- Covers all O1-O9 metrics in visual form
- Import via Grafana UI or provisioning
- Dashboard UID: poimen-memory-obs
- 11 alert rules across 5 groups
- Availability: service down, DB down, embedding down
- Latency: ingest p95 > 5s, query p95 > 2s, embedding p95 > 10s
- Errors: ingest/query error rate > 10%, embedding failures
- Storage: pool exhausted, write errors
- Quality: relevance precision < 30%
- PrometheusRule CRD for kube-prometheus-stack
feat(O13): relevance evaluation CronJob manifest
CI / CI (pull_request) Successful in 12m14s
9e85b1a063
- Runs every 6 hours with sample queries
- Tests query endpoint with known queries
- Reports precision (queries with results / total)
- Snapshots /metrics endpoint for monitoring
- Lightweight: curl-based, 16Mi memory
- Deploy: kubectl apply -f k8s/infra/relevance-eval-cronjob.yaml
rock added 1 commit 2026-09-13 12:54:30 +00:00
- MetricsSnapshot::capture() snapshots all metric values
- assert_counter_inc(): verify counter delta after scenario
- assert_gauge_eq(): verify gauge value
- assert_histogram_count_inc(): verify histogram observations
- assert_gauge_f64_approx(): verify f64 gauges with tolerance
- print_deltas(): debug helper for all changed metrics
- 9 scenario tests: ingest, query error, relevance batch, write
- Histogram fields made pub for snapshot access
- 515 total tests passing
rock added 1 commit 2026-09-13 13:03:01 +00:00
feat: user identity + error name tracking in metrics
CI / CI (pull_request) Successful in 12m36s
3e7344787e
- ERRORS_BY_USER: labeled counter {user_id, endpoint, error_name}
- REQUESTS_BY_USER: labeled counter {user_id, endpoint}
- extract_user_id(): decode JWT sub claim from Authorization header
- Error names: auth_failure, forbidden, rate_limited, bad_request, embedding_failure
- Ingest handler: tracks user_id from claims.sub
- Query handler: tracks user_id from JWT decode
- Context handler: tracks user_id from claims.sub
- render_labeled_counter(): generic Prometheus label renderer
- User identity from gateway JWT (claims.sub per API.md)
- 515 tests passing
rock added 1 commit 2026-09-13 13:12:55 +00:00
fix: replace labeled counters with named error counters
CI / CI (pull_request) Successful in 12m5s
f5c6bf5e5d
- Remove ERRORS_BY_CLASS, ERRORS_BY_USER, REQUESTS_BY_USER (overengineered)
- Add simple named counters per error type per endpoint:
  memory_error_auth_failure_ingest_total
  memory_error_forbidden_ingest_total
  memory_error_rate_limited_ingest_total
  memory_error_bad_request_ingest_total
  memory_error_db_error_ingest_total
  memory_error_auth_failure_query_total
  memory_error_forbidden_query_total
  memory_error_bad_request_query_total
  memory_error_embedding_failure_query_total
  memory_error_search_failure_query_total
  memory_error_auth_failure_context_total
  memory_error_forbidden_context_total
  memory_error_lookup_failure_context_total
- LAST_ERROR_TIMESTAMP gauge for most recent error
- 515 tests passing
rock added 1 commit 2026-09-13 13:17:11 +00:00
feat: unexpected error counter + user_id in error logs
CI / CI (pull_request) Successful in 12m31s
57c61b522b
- ERROR_UNEXPECTED_TOTAL: global unexpected error counter
- ERROR_UNEXPECTED_INGEST/QUERY/CONTEXT: per-endpoint unexpected errors
- All 500 error paths now increment unexpected counter
- Error logs include user_id for customer association:
  tracing::error!(user_id = claims.sub, "Unexpected error: ...")
- Covers: DB errors, search failures, temporal query failures
- 515 tests passing
rock merged commit 4169effd8a into main 2026-09-13 13:53:54 +00:00
rock deleted branch feat/observability-o1-o13 2026-09-13 13:53:54 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: riotpiao-poimen/poimen-memory#52