Observability
Everything below ships in the platform package’s cavs-node/observability/ folder:
Prometheus config
and rules, 13 Grafana dashboards, Alertmanager routing, Loki and Tempo configuration,
Grafana Alloy, a Grafana Cloud Terraform module, and 12 runbooks.
Metrics
Section titled “Metrics”Prometheus format on a dedicated internal listener:
METRICS_ENABLED=trueMETRICS_ADDR=:9464CAVS_REGION=us-central1 # a low-cardinality label on every metricWhat’s instrumented
Section titled “What’s instrumented”| Area | Metrics |
|---|---|
| HTTP golden signals | cavs_http_requests_total, cavs_http_request_duration_seconds, cavs_http_in_flight_requests, cavs_http_request_size_bytes, cavs_http_response_size_bytes, cavs_http_timeouts_total, cavs_http_panics_total, cavs_http_rate_limited_total |
| Auth & security | cavs_auth_attempts_total, cavs_auth_failures_total, cavs_permission_denied_total, cavs_token_revocations_total, cavs_api_key_expired_total, cavs_api_key_rotations_total, cavs_cross_tenant_access_blocked_total |
| Uploads | session created/completed/failed, active sessions, parts, bytes, duration, throughput |
| Downloads | cavs_download_requests_total (by result), cavs_download_bytes_total, cavs_download_duration_seconds, cavs_download_failures_total, cavs_download_signed_urls_total, cavs_download_signed_url_expired_total, cavs_download_checksum_failures_total |
| Storage & dedup | cavs_storage_logical_bytes, cavs_storage_physical_bytes, cavs_storage_saved_bytes, cavs_deduplication_ratio, cavs_deduplicated_bytes_total, cavs_chunks_total, cavs_chunks_created_total, cavs_chunks_reused_total, cavs_chunk_lookup_duration_seconds |
| Economics | cavs_storage_cost_estimated_usd, cavs_storage_cost_avoided_usd, cavs_storage_cost_per_logical_tb, cavs_storage_cost_per_physical_tb, cavs_storage_ledger_discrepancy_bytes |
| Workers & queues | cavs_jobs_{enqueued,started,completed,failed,retried,dead_letter}_total, cavs_job_duration_seconds, cavs_queue_depth, cavs_queue_oldest_job_age_seconds |
| Webhooks | deliveries by result, retries, failures, delivery duration |
| Billing | cavs_billing_mrr_usd, cavs_billing_arr_usd, active subscriptions, trials, upgrades, downgrades, cancellations, payment failures and recoveries, webhook failures |
| Signed URLs | cavs_signed_url_failures_total by operation |
Route labels are normalized (path parameters replaced by patterns), so cardinality stays bounded no matter how many repositories you have.
Tracing
Section titled “Tracing”OpenTelemetry server spans over OTLP/gRPC:
TRACING_ENABLED=trueOTEL_EXPORTER_OTLP_ENDPOINT=http://alloy:4317OTEL_EXPORTER_OTLP_INSECURE=trueOTEL_TRACES_SAMPLER_RATIO=0.1 # 10%Off by default; when disabled the middleware is a no-op, so it’s always safe to leave
installed. Sampling guidance is in observability/SAMPLING.md.
Logging
Section titled “Logging”Structured logs with the correlation id on every line. Since the id is also returned
in X-Request-Id and embedded in error bodies as request_id, a customer can quote a
single value that finds the exact request in your logs.
The access log records method, normalized route, status and byte counts. Loki configuration is included.
Cloudflare R2 exporter
Section titled “Cloudflare R2 exporter”A separate binary that scrapes provider-side analytics — storage bytes, class A/B operations — and reconciles them against CAVS’s own figures:
CF_ACCOUNT_ID=<account>CF_API_TOKEN=<token> # Account Analytics:Read + Workers R2 Storage:ReadR2_BUCKETS=cavs-prodR2_SCRAPE_INTERVAL=5mR2_RECONCILE=trueThis is how you catch the case where your bill and your metering disagree.
Dashboards
Section titled “Dashboards”Thirteen Grafana dashboards in observability/grafana/dashboards/:
| Dashboard | Answers |
|---|---|
cavs-executive-overview |
Is the business healthy? |
cavs-platform-health |
Is the platform up? |
cavs-api-performance |
Latency, throughput, error rates by route |
cavs-workers-queues |
Are events being consumed? Is the queue backing up? |
cavs-artifact-operations |
Upload and download volume and success |
cavs-deduplication |
Is dedup performing as expected? |
cavs-storage-economics |
Cost per TB, cost avoided |
cavs-customer-usage |
Per-tenant usage |
cavs-billing |
MRR, ARR, churn, payment failures |
cavs-security |
Auth failures, permission denials, cross-tenant blocks |
cavs-mongodb |
Database health |
cavs-cloudflare-r2 |
Provider-side storage and operations |
cavs-infrastructure |
CPU, memory, instances |
Grafana Cloud: observability/grafanacloud/ has a Terraform module,
import-dashboards.sh and verify-metrics.sh — run the last one after wiring a new
deployment to confirm cavs_* series are actually arriving.
| SLO | Target | Window |
|---|---|---|
| API availability | 99.9% | 30d |
| API read latency p95 | < 500 ms | 30d |
| Metadata write latency p95 | < 800 ms | 30d |
| Signed URL generation p95 | < 500 ms | 30d |
| Artifact finalize p95 | < 2 s | 30d |
| Upload success | 99.5% of sessions | 30d |
| Download success | 99.9% | 30d |
| Jobs on time | 99% | 30d |
Error budget at 99.9% availability: ~43 minutes/month.
1 - ( sum(increase(cavs_http_requests_total{status_code=~"5.."}[30d])) / clamp_min(sum(increase(cavs_http_requests_total[30d])), 1))( sum(increase(cavs_http_requests_total{status_code=~"5.."}[30d])) / clamp_min(sum(increase(cavs_http_requests_total[30d])), 1)) / 0.001Recording rules pre-compute cavs:availability:ratio5m and cavs:http_latency:p95, so
dashboards and alerts don’t recompute expensive queries. Full definitions in
observability/SLOS.md.
Alerts
Section titled “Alerts”Rules in observability/prometheus/rules/alerts.rules.yml, routing in
observability/alertmanager/. Each alert links to a runbook.
Runbooks
Section titled “Runbooks”Twelve, in observability/runbooks/:
| Runbook | For |
|---|---|
api-down |
The API isn’t serving |
mongo-unavailable |
Database unreachable |
r2-degraded |
Object storage degraded |
queue-backlog |
Events piling up |
upload-failures |
Uploads failing at rate |
checksum-failure |
Integrity verification failing |
ledger-discrepancy |
Metering diverging from reality |
billing-webhook-failure |
Provider events not landing |
backup-failure |
Backups failing |
disk-full |
Out of disk |
high-cpu / high-memory |
Resource saturation |
Local observability stack
Section titled “Local observability stack”cd observabilitydocker compose -f docker-compose.observability.yml upBrings up Prometheus, Grafana with the dashboards provisioned, Loki, Tempo, Alloy and Alertmanager against your local CAVS stack. The fastest way to see whether an instrumentation change works.
Retention
Section titled “Retention”Guidance in observability/RETENTION.md. Broadly: high-resolution metrics for weeks,
downsampled for months, traces sampled and short-lived, logs sized to your compliance
requirement.
Wiring a new deployment
Section titled “Wiring a new deployment”- Set
METRICS_ENABLED=true,METRICS_ADDR,CAVS_REGION; keep the port private. - Point Prometheus (or Alloy) at
METRICS_ADDRon every instance. - Load the recording and alert rules.
- Import the dashboards.
- Run
verify-metrics.shand confirmcavs_*series arrive. - Wire Alertmanager to your pager.
- Enable tracing at 10% and confirm spans land.
- Deploy the R2 exporter with
R2_RECONCILE=true. - Set
CHECKLIST.mdas your go-live gate.
- Configuration reference — the variables.
- Scaling — what the metrics will tell you to do.
- Deploying — the deployment path.

