.docker/observability/README.md
This directory contains the comprehensive observability stack for RustFS, designed to provide deep insights into application performance, logs, and traces.
The stack is composed of the following best-in-class open-source components:
By default, this stack uses Tempo in single-binary mode and does not require Kafka/Redpanda.
If you want the Kafka-backed HA Tempo path, use docker-compose-example-for-rustfs.yml together with docker-compose-tempo-ha-override.yml.
Three pre-built Grafana dashboards are included for monitoring RustFS GET performance optimization rollout:
| Dashboard | File | Description |
|---|---|---|
| GET Rollout Health | grafana-get-rollout-health.json | Monitors optimization rollout: latency by reader path, early-stop hit rate, codec streaming usage, pipeline failures |
| GET Data Integrity | grafana-get-data-integrity.json | Monitors data safety: bitrot verify failures, decode errors, short reads, shard read outcomes |
| GET Resource Impact | grafana-get-resource-impact.json | Monitors resource usage: concurrent requests, IO queue utilization, disk permit wait, RSS trend |
| Object Data Cache | grafana-object-data-cache.json | Monitors the GET body cache (rustfs_object_data_cache_*): hit ratio, lookup/plan/fill outcomes, fill duration quantiles, hit vs fill throughput, entries/weighted bytes, inflight fills, memory-pressure skips, invalidations, and size-class breakdowns |
The file prometheus-rules/rustfs-get-optimization-alerts.yaml contains pre-configured alerting rules:
| Alert | Severity | Condition |
|---|---|---|
GetP99Regression | Critical | GET p99 latency > 2x baseline for 10m |
PipelineFailureSpike | Critical | Pipeline failure rate > 5x baseline for 5m |
BitrotMismatchSpike | Critical | Bitrot mismatch rate > 3x baseline for 5m |
EarlyStopInsufficientQuorum | Warning | Early-stop insufficient quorum rate > 0.1/s for 5m |
CodecStreamingFallbackSpike | Warning | Codec streaming fallback > 10x baseline for 10m |
IoQueueSaturation | Warning | IO queue utilization > 90% for 5m |
The file prometheus-rules/rustfs-kms-alerts.yml contains alerting rules for the KMS backend operation metrics. Thresholds are conservative defaults pending staging baseline calibration; response procedures live in docs/operations/kms-observability-runbook.md, and the matching dashboard is deploy/observability/grafana/rustfs-kms-observability.json.
| Alert | Severity | Condition |
|---|---|---|
KmsBackendFatalErrors | Critical | Fatal (non-retryable) attempt failures > 0 for 5m |
KmsBackendHighErrorRate | Critical | Non-success operation ratio > 5% for 10m (with traffic guard) |
KmsBackendP99LatencyHigh | Warning | Operation p99 duration (incl. retries) > 2s for 10m |
KmsBackendAttemptFailureSpike | Warning | Attempt failure rate > 0.5/s for 10m |
KmsBackendRetryBudgetExhausted | Warning | budget_exhausted / deadline_exceeded outcomes > 0.05/s for 10m |
Add the alert rules file to your Prometheus configuration:
# prometheus.yml
rule_files:
- "/etc/prometheus/rules/*.yml"
# Or mount the file in docker-compose.yml:
# volumes:
# - ./prometheus-rules:/etc/prometheus/rules
The dashboards are automatically provisioned when Grafana starts. They use the ${DS_PROMETHEUS} datasource variable, so you need a Prometheus datasource configured in Grafana.
Key panels to monitor during optimization rollout:
codec_streaming vs legacy_duplex latencyRun the following command to start the entire stack:
docker compose up -d
The default docker-compose.yml is the single-node stack.
If you need the Kafka-backed HA Tempo configuration, start it with:
docker compose -f docker-compose-example-for-rustfs.yml -f docker-compose-tempo-ha-override.yml up -d
| Service | URL | Credentials | Description |
|---|---|---|---|
| Grafana | http://localhost:3000 | admin / admin | Main visualization hub. |
| Prometheus | http://localhost:9090 | - | Metric queries and status. |
| Jaeger UI | http://localhost:16686 | - | Secondary trace visualization. |
| Tempo | http://localhost:3200 | - | Tempo status/metrics. |
Data is stored in the following Docker volumes:
prometheus-data: Prometheus metricstempo-data: Tempo traces (WAL and Blocks)loki-data: Loki logs (Chunks and Rules)jaeger-data: Jaeger traces (Badger DB)To clear all data:
docker compose down -v
prometheus.yml to add scrape targets or alerting rules.grafana/ directory.otel-collector-config.yaml to modify pipelines, processors, or exporters.When RustFS points RUSTFS_OBS_ENDPOINT at this stack, treat the value as the
OTLP/HTTP base URL, for example:
export RUSTFS_OBS_ENDPOINT=http://host.docker.internal:4318
RustFS automatically expands that base URL to:
/v1/traces/v1/metrics/v1/logsImportant behavior notes:
tracing fields as log attributes. Loki stores
those attributes as structured metadata, and the Collector also mirrors the
common troubleshooting fields into the log line so simple line filters can
find them.RUSTFS_OBS_LOGGER_LEVEL=info keeps the top-level request span but filters
many nested debug spans. If Tempo or Jaeger looks sparse, retry with
RUSTFS_OBS_LOGGER_LEVEL=debug before suspecting collector or Tempo issues.Minimal validation flow:
# 1. Start this observability stack.
docker compose up -d
# 2. Start RustFS with OTLP/HTTP export and richer span visibility.
export RUSTFS_OBS_ENDPOINT=http://host.docker.internal:4318
export RUSTFS_OBS_LOGGER_LEVEL=debug
# 3. Generate real request traffic.
curl -I http://127.0.0.1:9000/health
curl -I http://127.0.0.1:9000/health/ready
# 4. Inspect Grafana or Jaeger.
# Grafana: http://localhost:3000
# Jaeger: http://localhost:16686
For a structured RustFS log such as an inter-node RPC authentication failure,
the Loki line now includes fields such as event, component, subsystem,
failure_reason, rpc_service, rpc_method, and expected_audience. Useful
LogQL checks:
{service_name="RustFS"} |= "RPC signature verification failed"
{service_name="RustFS"} |= "failure_reason="
{service_name="RustFS"} | failure_reason != ""
If logs and metrics are present but traces are sparse, the most common cause is
"no real request traffic yet" or "info level filtered nested spans", not an
OTLP routing failure.
docker compose ps.docker compose logs -f <service_name>.http://localhost:13133 for health status and http://localhost:1888/debug/pprof/ for profiling.