Files
rippled/docker/telemetry/docker-compose.yml
Pratik Mankawde 19f49cf961 docs(telemetry): explain the telemetry dependency loop and the Compose floor
Two comment-only notes.

MetricsRegistry.cpp: record why the app and overlay includes exist and
what they cost. They are what makes loops.txt carry
xrpld.app <-> xrpld.telemetry and xrpld.overlay <-> xrpld.telemetry, where
ordering.txt previously had telemetry strictly below both. The observable
gauges are pull-model, so their callbacks need the concrete types to
sample live state. The cycle is confined to this translation unit: no
telemetry header includes app or overlay, and all of src/xrpld builds
into one target, so there is no header or link cycle. Inverting it needs
a metrics-source interface below overlay, which is left as follow-up.
Also note loops.txt is generated and must never be hand-edited.

docker-compose.yml: state the Compose >= 2.24.0 floor. The grafana
service uses the long-form env_file mapping, which older Compose cannot
parse, and it fails for the whole file rather than that one service. The
long form is required because .env.alerting is gitignored and absent in a
fresh clone, and the short form treats a missing env file as an error.
2026-08-14 21:45:09 +01:00

171 lines
7.2 KiB
YAML

# Docker Compose stack for xrpld OpenTelemetry observability.
#
# Provides services for local development:
# - otel-collector: receives OTLP traces from xrpld, batches and
# forwards them to Tempo. Also tails xrpld log files
# via filelog receiver and exports to Loki. Listens on ports
# 4317 (gRPC) and 4318 (HTTP).
# - tempo: Grafana Tempo tracing backend, queryable via Grafana Explore
# on port 3000. Recommended for production (S3/GCS storage, TraceQL).
# - loki: Grafana Loki log aggregation backend for centralized log
# ingestion and log-trace correlation (Phase 8).
# - grafana: dashboards on port 3000, pre-configured with Tempo,
# Prometheus, and Loki datasources.
#
# Requires Docker Compose >= 2.24.0. The grafana service uses the long-form
# `env_file` mapping (`path:` / `required:`), which older Compose cannot parse —
# and it fails for the whole file, not just that service. The long form is
# needed: `.env.alerting` is gitignored and absent in a fresh clone, and the
# short form treats a missing env file as an error.
#
# Usage:
# docker compose -f docker/telemetry/docker-compose.yml up -d
#
# Configure xrpld to export traces by adding to xrpld.cfg:
# [telemetry]
# enabled=1
# endpoint=http://localhost:4318/v1/traces
services:
# OpenTelemetry Collector: receives spans from xrpld via OTLP protocol,
# batches them for efficiency, and forwards to Tempo for storage.
otel-collector:
image: otel/opentelemetry-collector-contrib:0.158.0
command: ["--config=/etc/otel-collector-config.yaml"]
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP (traces + native OTel metrics)
- "8889:8889" # Prometheus metrics (spanmetrics + OTLP)
# StatsD UDP port removed — beast::insight now uses native OTLP.
# Uncomment if using server=statsd fallback:
# - "8125:8125/udp"
volumes:
# Mount collector pipeline config (receivers → processors → exporters)
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
# Mount the xrpld log root for the filelog receiver. The telemetry
# configs write to docker/telemetry/data/logs/<network>/debug.log, so
# the default source is the repo-relative ./data/logs — user-owned and
# needing no root, so `docker compose up` works with no setup. Override
# XRPLD_LOG_DIR to point at another root (e.g. the integration test sets
# it to its own workdir). Mounted read-only so the collector only tails.
- ${XRPLD_LOG_DIR:-./data/logs}:/var/log/xrpld:ro
depends_on:
- tempo
- loki
networks:
- xrpld-telemetry
# Grafana Tempo: distributed tracing backend that stores and indexes
# spans. Queryable via TraceQL in Grafana Explore.
tempo:
image: grafana/tempo:2.9.4
command: ["-config.file=/etc/tempo.yaml"]
ports:
- "3200:3200" # Tempo HTTP API (health check, query)
volumes:
# Mount Tempo storage and ingestion config
- ./tempo.yaml:/etc/tempo.yaml:ro
# Persistent volume for trace data (WAL + blocks)
- tempo-data:/var/tempo
networks:
- xrpld-telemetry
# Grafana Loki for centralized log ingestion and log-trace
# correlation. Loki 3.x supports native OTLP ingestion, so the OTel
# Collector exports via otlphttp to Loki's /otlp endpoint.
# Query logs via Grafana Explore -> Loki at http://localhost:3000.
loki:
image: grafana/loki:3.7.6
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki-data:/loki
networks:
- xrpld-telemetry
prometheus:
# Pinned to an exact patch release for reproducible, config-stable runs.
image: prom/prometheus:v3.13.2
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
depends_on:
- otel-collector
networks:
- xrpld-telemetry
# Grafana: visualization UI with Tempo pre-configured as a datasource.
# Anonymous admin access enabled for local development convenience.
grafana:
image: grafana/grafana:13.1.2
# Alerting secrets/addresses (Slack webhook, alert email) come from this
# gitignored file; Grafana expands the ${VARS} referenced in the alerting
# provisioning YAML. Absent file = unset vars = receivers have no live
# destination, which is fine for a local stack. See .env.alerting.example.
env_file:
- path: .env.alerting
required: false
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true # No login required for local dev
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin # Full access without auth
# Remote image rendering: point Grafana at the renderer container.
# These belong on the grafana service (the server delegates renders);
# the callback URL is how the renderer fetches the panel from grafana.
- GF_RENDERING_SERVER_URL=http://renderer:8081/render
- GF_RENDERING_CALLBACK_URL=http://grafana:3000/
# Grafana 13 turns the renderAuthJWT feature toggle on by default, which
# makes the renderer reject requests unless both sides share a token that
# is not the "-" default. Must match AUTH_TOKEN on the renderer service.
- GF_RENDERING_RENDERER_TOKEN=${GF_RENDERING_RENDERER_TOKEN:-xrpld-local-render}
# SMTP for the critical-tier email receiver and the Slack webhook / email
# address for the contact points all come from the env_file above, which
# injects them straight into the container environment for Grafana to
# expand. They are deliberately NOT duplicated here: a compose-level
# `environment:` entry is interpolated from the host shell and would
# override (and blank out) the env_file values.
ports:
- "3000:3000" # Grafana web UI
volumes:
# Auto-provision Tempo datasource and search filters on startup
- ./grafana/provisioning:/etc/grafana/provisioning:ro
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
depends_on:
- tempo
- prometheus
- loki
- renderer
networks:
- xrpld-telemetry
# Grafana image renderer: a sidecar that renders panels/dashboards to PNG
# for image export and alerting. Grafana calls it at http://renderer:8081.
renderer:
# Pinned like every other image in this stack so a stack that worked
# yesterday still works today. Upstream maintains only the newest release,
# which is expected to serve all supported Grafana versions.
image: grafana/grafana-image-renderer:v5.12.0
environment:
# Shared secret for the JWT-authenticated render requests Grafana 13
# sends. Must match GF_RENDERING_RENDERER_TOKEN on the grafana service.
- AUTH_TOKEN=${GF_RENDERING_RENDERER_TOKEN:-xrpld-local-render}
ports:
- "8081:8081" # Renderer HTTP endpoint (called by grafana)
networks:
- xrpld-telemetry
# Named volume for Tempo trace storage (WAL and compacted blocks).
# Data persists across container restarts. Remove with:
# docker compose -f docker/telemetry/docker-compose.yml down -v
volumes:
tempo-data:
prometheus-data:
loki-data:
# Isolated bridge network so services communicate by container name
# (e.g., the collector reaches Tempo at http://tempo:4317).
networks:
xrpld-telemetry:
driver: bridge