1{ 2 "uid": "factory-infra", 3 "title": "Factory — Infra", 4 "tags": ["factory", "observability", "infra"], 5 "timezone": "browser", 6 "schemaVersion": 39, 7 "version": 1, 8 "editable": true, 9 "refresh": "30s", 10 "time": { "from": "now-6h", "to": "now" }, 11 "panels": [ 12 { 13 "id": 1, 14 "type": "timeseries", 15 "title": "Node disk usage (mountpoint /var/lib)", 16 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 17 "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, 18 "fieldConfig": { "defaults": { "unit": "percentunit", "decimals": 1, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 0.8 } ] } }, "overrides": [] }, 19 "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "thresholds": { "mode": "absolute" } }, 20 "targets": [ { "refId": "A", "expr": "node_filesystem_usage{mountpoint=\"/var/lib\"}", "legendFormat": "{{instance}}" } ] 21 }, 22 { 23 "id": 2, 24 "type": "timeseries", 25 "title": "Node CPU usage (1 m)", 26 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 27 "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 }, 28 "fieldConfig": { "defaults": { "unit": "percentunit", "custom": { "drawStyle": "line" } }, "overrides": [] }, 29 "options": { "legend": { "displayMode": "list", "placement": "bottom" } }, 30 "targets": [ { "refId": "A", "expr": "1 - avg by (instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[1m]))", "legendFormat": "{{instance}}" } ] 31 }, 32 { 33 "id": 3, 34 "type": "timeseries", 35 "title": "Node memory usage", 36 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 37 "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 }, 38 "fieldConfig": { "defaults": { "unit": "percentunit", "custom": { "drawStyle": "line" } }, "overrides": [] }, 39 "options": { "legend": { "displayMode": "list", "placement": "bottom" } }, 40 "targets": [ { "refId": "A", "expr": "1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes", "legendFormat": "{{instance}}" } ] 41 }, 42 { 43 "id": 4, 44 "type": "timeseries", 45 "title": "DB query p95 per app (10 m) — pool pressure proxy", 46 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 47 "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 }, 48 "fieldConfig": { "defaults": { "unit": "s", "custom": { "drawStyle": "line" } }, "overrides": [] }, 49 "options": { "legend": { "displayMode": "list", "placement": "bottom" } }, 50 "targets": [ 51 { "refId": "A", "expr": "histogram_quantile(0.95, sum by (le) (rate(db_query_duration_seconds_bucket{service_name=\"factory-api\"}[10m])))", "legendFormat": "api" }, 52 { "refId": "B", "expr": "histogram_quantile(0.95, sum by (le) (rate(db_query_duration_seconds_bucket{service_name=\"factory-worker\"}[10m])))", "legendFormat": "worker" } 53 ] 54 }, 55 { 56 "id": 5, 57 "type": "timeseries", 58 "title": "Redis command p95 per app (10 m) — hit-rate pressure proxy", 59 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 60 "gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 }, 61 "fieldConfig": { "defaults": { "unit": "s", "custom": { "drawStyle": "line" } }, "overrides": [] }, 62 "options": { "legend": { "displayMode": "list", "placement": "bottom" } }, 63 "targets": [ 64 { "refId": "A", "expr": "histogram_quantile(0.95, sum by (le) (rate(redis_command_duration_seconds_bucket{service_name=\"factory-api\"}[10m])))", "legendFormat": "api" }, 65 { "refId": "B", "expr": "histogram_quantile(0.95, sum by (le) (rate(redis_command_duration_seconds_bucket{service_name=\"factory-worker\"}[10m])))", "legendFormat": "worker" } 66 ] 67 }, 68 { 69 "id": 6, 70 "type": "timeseries", 71 "title": "Storage ops (S3/MinIO) rate + p95 by op", 72 "datasource": { "type": "prometheus", "uid": "factory-prometheus" }, 73 "gridPos": { "h": 8, "w": 12, "x": 12, "y": 16 }, 74 "fieldConfig": { "defaults": { "unit": "ops", "custom": { "drawStyle": "line" } }, "overrides": [] }, 75 "options": { "legend": { "displayMode": "list", "placement": "bottom" } }, 76 "targets": [ 77 { "refId": "A", "expr": "sum by (op) (rate(storage_ops_total{service_name=~\"factory-(api|worker)\"}[5m]))", "legendFormat": "{{op}} /s" }, 78 { "refId": "B", "expr": "histogram_quantile(0.95, sum by (le, op) (rate(storage_op_duration_seconds_bucket{service_name=~\"factory-(api|worker)\"}[10m])))", "legendFormat": "{{op}} p95 (s)" } 79 ] 80 } 81 ], 82 "annotations": { 83 "list": [ 84 { 85 "builtIn": 1, 86 "datasource": { "type": "grafana", "uid": "-- Grafana --" }, 87 "name": "Pod/PG/OS gauges — SPEC GAP", 88 "description": "The spec's Infra dashboard names 'CPU/mem per pod, PG connections vs pool, disk, Redis hit rate, OpenSearch cluster health'. Only disk/CPU/mem (node-exporter, expected-present) + app-side proxies (db/redis p95, storage ops) come from the spec's 14-metric set. Per-pod cgroup metrics (kubelet/cadvisor), PG connection pool gauges, redis hit rate and OpenSearch cluster health are EXPORTER-DEPENDENT metrics outside the 14-set — recorded in infrastructure/observability/README.md (spec-conflict, AGENTS rule 29); the panels use the app-side proxies available from the shipped metrics.", 89 "enable": true, 90 "hide": false, 91 "iconColor": "rgba(255, 96, 96, 1)" 92 } 93 ] 94 } 95} 96