tidaldb/docs/ops/grafana-tidaldb.json
jordan 4766f566de feat(observability): HTTP metrics, structured logs, dashboard, live tidalctl
There was no metric anywhere that could answer "how much traffic are we serving"
or "what is our error rate". The engine published a rich DOMAIN surface (search
latency, WAL fsync, quorum timeouts, replication lag) and nothing about HTTP, so
a cluster could serve 401s or 503s indefinitely with every existing gauge looking
healthy. Logs were collected but unusable. There was no way to ask a RUNNING node
anything.

1. HTTP metrics. tidaldb_http_requests_total{route,method,status} plus a
   per-route duration histogram, recorded by one layer placed OUTSIDE the auth,
   timeout and rate-limit layers so it sees the status actually returned to the
   client. Cardinality is the whole design: the route label is axum's MatchedPath
   TEMPLATE, not the path, and unmatched requests collapse into one <unmatched>
   bucket so a 404 flood cannot mint series. A hard cap folds anything past it
   into an overflow bucket while established series keep counting.

   The engine owns the /metrics listener but must not learn what a route or a
   status code is, so it gained one registration hook
   (MetricsState::set_extra_renderer) and tidal-server publishes through it. One
   scrape target per node, not two.

2. Structured logs. The previous init was a bare tracing_subscriber::fmt(), which
   produced two real defects: ANSI escapes leaked into collected logs, and every
   line failed the collector's JSON parse and was stamped level=info — so
   `level:error` matched NOTHING and errors were invisible to the log platform
   while being collected. JSON_LOGS=1 emits the collector's exact wire format
   (ts/level/service/env/msg), span fields are lifted so request_id lands on every
   line of a request, and ANSI is off unconditionally in both formats.

   Verified against the running binary, which caught a defect no unit test would
   have: dependencies logging through the `log` crate arrived with target="log"
   and four log.* metadata fields (absolute cargo registry paths, indexed
   forever). The real module is now lifted into target and the bridge metadata
   pruned.

3. Dashboard. docs/ops/grafana-tidaldb.json, 13 panels, mirrored into the fleet
   as a grafana-database-dashboards key. Every metric name was checked against a
   live endpoint and all 26 PromQL expressions were executed against the live
   TSDB before commit, because a dashboard full of "No data" is worse than none.
   Confirmed loaded in Grafana (uid tidaldb-overview, Databases folder).

4. tidalctl live mode. Every other subcommand reads a data dir AT REST, some
   requiring a stopped node. `search`, `feed`, `cluster-status` and `watch` take
   --url and talk to a running server, with --ca/--insecure because a cluster's
   client port is served with the INTERNAL cluster CA. Exit codes follow the crate
   contract, so `tidalctl cluster-status && deploy` gates on convergence.

   Its first real run immediately found a reporting defect: the aggregated
   /cluster/status reported two HEALTHY peers as UNREACHABLE PARTITIONED at 13.3M
   lag, having derived lag against an uninitialised applied=0, while every node's
   own status reported lag=0, reseed=false and identical frontiers, with
   pod-to-pod connectivity open and nothing logged. cluster-status now names that
   signature "NO REPORT (aggregated view; query the node directly)" instead of
   repeating it as replication lag; a genuine non-zero-applied lag still reports
   BEHIND. The underlying gap is documented as open work in
   docs/ops/observability.md.

Verified: 2101 + 175 engine/server unit tests, 8 standalone integration (3 new,
including the cardinality proof and the cross-crate metrics seam), 23 tidalctl
(10 new), reseed + catchup + admin-gate e2e green, clippy clean, and both the
metrics and the log format exercised against a real running binary.
2026-08-23 10:31:57 -06:00

1170 lines
30 KiB
JSON

{
"annotations": {
"list": []
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"liveNow": false,
"panels": [
{
"id": 1,
"type": "row",
"title": "HTTP surface \u2014 usage and errors",
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"panels": []
},
{
"id": 2,
"type": "timeseries",
"title": "Request rate by route",
"description": "Requests per second by matched route TEMPLATE. Before tidaldb_http_requests_total existed there was no metric anywhere that could answer 'how much traffic are we serving'.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 1
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 40,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "normal"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum by (route) (rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "{{route}}",
"range": true,
"refId": "A"
}
]
},
{
"id": 3,
"type": "timeseries",
"title": "Requests by status",
"description": "Exact status codes, not classes: 401 (no/bad credential) vs 403 (valid data bearer, not an operator) vs 429 (rate limited) vs 503 (quorum timeout) are different incidents.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 1
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 40,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "normal"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum by (status) (rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "{{status}}",
"range": true,
"refId": "A"
}
]
},
{
"id": 4,
"type": "stat",
"title": "5xx ratio",
"description": "Server-fault share of served requests. clamp_min keeps an idle cluster from dividing by zero and painting red.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 6,
"w": 4,
"x": 0,
"y": 9
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 0.01
},
{
"color": "red",
"value": 0.05
}
]
},
"mappings": [],
"unit": "percentunit",
"decimals": 2
},
"overrides": []
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNonNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\",status=~\"5..\"}[$__rate_interval])) / clamp_min(sum(rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])), 0.001)",
"legendFormat": "5xx share",
"range": true,
"refId": "A"
}
]
},
{
"id": 5,
"type": "timeseries",
"title": "Auth rejections (401 / 403)",
"description": "401 = missing/invalid credential. 403 = a valid DATA bearer used against an operator verb, i.e. a client trying to reach /cluster/*. A sustained 403 rate is a client misconfigured with the wrong key, or someone probing.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 6,
"w": 10,
"x": 4,
"y": 9
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum by (status, route) (rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\",status=~\"401|403\"}[$__rate_interval]))",
"legendFormat": "{{status}} {{route}}",
"range": true,
"refId": "A"
}
]
},
{
"id": 6,
"type": "timeseries",
"title": "HTTP p99 by route",
"description": "End-to-end latency as the CLIENT sees it, including auth, queueing behind the concurrency cap, and the leader forward. The engine's own latency series exclude all of that.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 6,
"w": 10,
"x": 14,
"y": 9
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "ms",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.99, sum by (route, le) (rate(tidaldb_http_request_duration_us_bucket{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))) / 1000",
"legendFormat": "{{route}}",
"range": true,
"refId": "A"
}
]
},
{
"id": 7,
"type": "row",
"title": "Query engine latency",
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 15
},
"panels": []
},
{
"id": 8,
"type": "timeseries",
"title": "Search latency",
"description": "Search percentiles published directly by the engine.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 0,
"y": 16
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "ms",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_search_latency_us_p50{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p50",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_search_latency_us_p95{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p95",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_search_latency_us_p99{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p99",
"range": true,
"refId": "C"
}
]
},
{
"id": 9,
"type": "timeseries",
"title": "Retrieve latency",
"description": "Retrieve percentiles published directly by the engine.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 8,
"y": 16
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "ms",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_retrieve_latency_us_p50{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p50",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_retrieve_latency_us_p95{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p95",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_retrieve_latency_us_p99{namespace=~\"$namespace\",pod=~\"$pod\"} / 1000",
"legendFormat": "p99",
"range": true,
"refId": "C"
}
]
},
{
"id": 10,
"type": "timeseries",
"title": "Signal write p99",
"description": "Write path. WAL group-commit fsync is plotted alongside because it is usually the reason a write p99 moves.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 16,
"y": 16
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "ms",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.99, sum by (le) (rate(tidaldb_signal_write_latency_us_bucket{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))) / 1000",
"legendFormat": "p99",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "histogram_quantile(0.99, sum by (le) (rate(tidaldb_cluster_wal_fsync_us_bucket{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))) / 1000",
"legendFormat": "WAL fsync p99",
"range": true,
"refId": "B"
}
]
},
{
"id": 11,
"type": "row",
"title": "Cluster correctness",
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 23
},
"panels": []
},
{
"id": 12,
"type": "timeseries",
"title": "Replication lag",
"description": "Events this replica is behind the leader. Sustained non-zero means a follower is not keeping up; a step change usually follows a leader change.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 0,
"y": 24
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_replication_lag_seqno{namespace=~\"$namespace\",pod=~\"$pod\"}",
"legendFormat": "{{pod}}",
"range": true,
"refId": "A"
}
]
},
{
"id": 13,
"type": "timeseries",
"title": "Correctness counters",
"description": "scatter degraded is the one to watch: a 200 answered with PARTIAL results because a shard errored or missed its deadline. It is a CORRECTNESS signal that looks like success to the client.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 8,
"y": 24
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_cluster_quorum_timeouts_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "quorum timeouts",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_cluster_forward_failures_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "forward failures",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_cluster_scatter_degraded_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "scatter degraded",
"range": true,
"refId": "C"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_cluster_leader_changes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "leader changes",
"range": true,
"refId": "D"
}
]
},
{
"id": 14,
"type": "stat",
"title": "Fleet state",
"description": "health 0 or reseed pending 1 means a node is not serving normally. A reseed marker that persists past a restart is the m11p5 livelock signature.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 8,
"x": 16,
"y": 24
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"mappings": []
},
"overrides": []
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNonNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "min(tidaldb_health_ok{namespace=~\"$namespace\",pod=~\"$pod\"})",
"legendFormat": "health",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "max(tidaldb_cluster_reseed_required{namespace=~\"$namespace\",pod=~\"$pod\"})",
"legendFormat": "reseed pending",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "max(tidaldb_usearch_vector_count{namespace=~\"$namespace\",pod=~\"$pod\"})",
"legendFormat": "vectors",
"range": true,
"refId": "C"
}
]
},
{
"id": 15,
"type": "row",
"title": "Capacity and backpressure",
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 31
},
"panels": []
},
{
"id": 16,
"type": "timeseries",
"title": "Shed load",
"description": "Load actively shed. NOTE: tidalDB's own limiter is UNLIMITED unless TIDAL_RATE_LIMIT_RPS is set, and it keys per PRINCIPAL \u2014 with one shared bearer every caller is one principal, so this is an aggregate cap, not fairness.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 12,
"x": 0,
"y": 32
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps",
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_rate_limited_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "rate limited",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(rate(tidaldb_cluster_write_pool_rejections_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))",
"legendFormat": "write pool rejections",
"range": true,
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum by (status) (rate(tidaldb_http_requests_total{namespace=~\"$namespace\",pod=~\"$pod\",status=~\"429|408\"}[$__rate_interval]))",
"legendFormat": "http {{status}}",
"range": true,
"refId": "C"
}
]
},
{
"id": 17,
"type": "timeseries",
"title": "Durability backlog",
"description": "Uncompacted WAL and time since the last successful checkpoint. A checkpoint age that only climbs means the checkpoint thread is wedged \u2014 recovery time grows with it.",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"gridPos": {
"h": 7,
"w": 12,
"x": 12,
"y": 32
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"lineWidth": 2,
"showPoints": "never",
"stacking": {
"group": "A",
"mode": "none"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"min": 0
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_wal_lag_bytes{namespace=~\"$namespace\",pod=~\"$pod\"}",
"legendFormat": "WAL lag bytes {{pod}}",
"range": true,
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "tidaldb_checkpoint_age_seconds{namespace=~\"$namespace\",pod=~\"$pod\"}",
"legendFormat": "checkpoint age {{pod}}",
"range": true,
"refId": "B"
}
]
}
],
"refresh": "30s",
"schemaVersion": 39,
"tags": [
"tidaldb",
"database"
],
"templating": {
"list": [
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(tidaldb_health_ok, namespace)",
"hide": 0,
"includeAll": true,
"label": "namespace",
"multi": true,
"name": "namespace",
"options": [],
"query": {
"query": "label_values(tidaldb_health_ok, namespace)",
"refId": "A"
},
"refresh": 2,
"sort": 1,
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(tidaldb_health_ok{namespace=~\"$namespace\"}, pod)",
"hide": 0,
"includeAll": true,
"label": "pod",
"multi": true,
"name": "pod",
"options": [],
"query": {
"query": "label_values(tidaldb_health_ok{namespace=~\"$namespace\"}, pod)",
"refId": "A"
},
"refresh": 2,
"sort": 1,
"type": "query"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "utc",
"title": "tidalDB \u2014 usage, errors, and cluster health",
"uid": "tidaldb-overview",
"version": 1,
"weekStart": "",
"description": "tidalDB usage, errors, and cluster health. PRODUCT-SIDE SOURCE OF TRUTH: this file lives in the tidalDB repo at docs/ops/grafana-tidaldb.json and is mirrored into the fleet as the tidaldb-overview.json key of the grafana-database-dashboards ConfigMap (deployments/k8s/base/observability/database-dashboards.yaml), the same convention docs/ops/prometheus-alerts.yaml follows. Edit here, then mirror. Every expression was validated against the live TSDB; the label set is namespace/pod/container/partition_id as attached by vmagent's annotation-based pod discovery."
}