Files
rippled/docker/telemetry/tempo.yaml
Pratik Mankawde a214db3a90 docs(telemetry): remove pre-squash and plan-internal references from sync diagnostics
Comments across the sync-diagnostic work described earlier revisions of the same
change, or cited identifiers a reader of the merged tree cannot resolve.

Prior-state comparisons rewritten in the present tense:

- MetricsRegistry.cpp carried two adjacent paragraphs prescribing opposite
  behaviour for a disabled quorum, one publishing int64 max and one omitting
  the series. The code omits it; the superseded paragraph is gone and the
  surviving reason SIZE_MAX must not be cast is kept.
- MallocTrim, LedgerMaster, LedgerReplayTask, TransactionAcquire, Application:
  say what the signal is the only record of, rather than what was 'previously
  trace-only', 'not logged at all here' or 'used to sit inside if (debug())'.
- LedgerMaster.h and SpanGuardScope: without an explicit join each ledger's
  spans WOULD be separate traces -- not that they were 'before this'.
- Handshake: the message is forwarded byte for byte, not 'byte-identical to the
  previous behaviour', and the helper throws rather than 'throws as before'.
- MetricNames: quorum_disabled is a separate boolean rather than a sentinel,
  stated without what the state 'used to be encoded by'.
- LedgerMaster.cpp no longer claims to mirror the unl_quorum gauge; it does not.
  That gauge omits the series while this stores int64 max.
- 'Split out of' / 'Split from' become 'Kept separate from' in five places.

Plan-internal identifiers removed:

- All 24 WP-Ax / WP-Bx work-package labels across the telemetry tests, the
  collector configs, tempo.yaml and the expected_* inventories. They are defined
  in no file in the repo, so they resolve nowhere once merged.
- The two references to OpenTelemetryPlan/, which does not reach develop, now
  point at docs/telemetry-glossary.md 'Fresh-node sync diagnostics'.

Comments and JSON note strings only, no behaviour change.
2026-09-02 19:48:18 +01:00

150 lines
6.2 KiB
YAML

# Grafana Tempo configuration for xrpld telemetry stack.
#
# Runs in single-binary mode for local development.
# Receives traces via OTLP/gRPC from the OTel Collector and stores
# them locally. Queryable via Grafana Explore using the Tempo datasource.
#
# Search filters are configured on the Grafana datasource side
# (grafana/provisioning/datasources/tempo.yaml). Tempo auto-indexes
# all span attributes for search in single-binary mode.
#
# For production, replace local storage with S3/GCS backend and adjust
# retention via the compactor settings. See:
# https://grafana.com/docs/tempo/latest/configuration/
stream_over_http_enabled: true
server:
http_listen_port: 3200
# Raise the TraceQL metrics query range limit. The default
# query_frontend.metrics.max_duration is 3h, so a dashboard set to a longer
# window (e.g. 6h/12h) fails with "range exceeds 3h0m0s". 168h matches the
# search max_duration and gives dashboards generous headroom.
query_frontend:
metrics:
max_duration: 168h
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
ingester:
max_block_duration: 5m
compactor:
compaction:
block_retention: 1h
# Enable metrics generator for service graph, span metrics, and the
# local-blocks processor. Produces RED metrics (rate, errors, duration) per
# service/span for the service map, and keeps recent trace blocks queryable so
# TraceQL metrics queries (quantile_over_time, count_over_time, etc. via
# /api/metrics/query_range) work.
metrics_generator:
registry:
external_labels:
source: tempo
storage:
path: /var/tempo/generator/wal
# Uncomment and add a Prometheus service to docker-compose.yml
# to enable remote_write for service graph metrics:
# remote_write:
# - url: http://prometheus:9090/api/v1/write
# Separate WAL the local-blocks processor flushes traces to for metrics
# queries. Required when flush_to_storage is true.
traces_storage:
path: /var/tempo/generator/traces
processor:
local_blocks:
# xrpld consensus/transaction spans are SPAN_KIND_INTERNAL. By default
# local-blocks keeps only server spans for TraceQL metrics, so attribute
# aggregations over internal spans return nothing. Keep all spans.
filter_server_spans: false
# Flush recent blocks to traces_storage so query_range can read them.
flush_to_storage: true
overrides:
defaults:
metrics_generator:
processors:
- service-graphs
- span-metrics
- local-blocks
storage:
trace:
backend: local
wal:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
block:
# Give the highest-value span attributes their own Parquet columns so
# TraceQL scopes a search to one ledger without scanning the generic
# attribute list. Tempo indexes every attribute for search regardless;
# a dedicated column only changes the cost of filtering on it.
#
# ledger_hash is here rather than in the collector's spanmetrics
# `dimensions:` on purpose: it is a per-ledger value, so as a metric
# dimension it would mint one series per ledger acquired (unbounded
# cardinality). As a trace column it gives the same per-ledger lookup at
# zero metric cost -- which is how a single stuck or abandoned
# ledger.acquire is found: {name="ledger.acquire" && span.outcome=
# "abandoned" && span.ledger_hash="<hash>"}.
#
# txset_hash and remote_endpoint are here for the same reason and by the
# same rule: a tx-set root hash is one value per consensus round and a
# peer endpoint is one value per address dialled, so either as a
# spanmetrics dimension would mint an unbounded number of metric series.
# As trace columns they answer the per-object questions the metrics
# cannot -- which proposed set stalled a round:
# {name="txset.acquire" && span.outcome="timeout" &&
# span.txset_hash="<hash>"}
# and which peer a dial keeps failing against:
# {name="peer.dial" && span.outcome="tcp_fail" &&
# span.remote_endpoint="10.0.0.5:51235"}
#
# missing_nodes, served_nodes and duration_ms are deliberately NOT given
# columns. They are unbounded integers, so they are useless as equality
# filters; Tempo indexes every attribute for search regardless, so they
# remain queryable by range (e.g. span.missing_nodes > 0) at no
# storage cost, which is how they are actually read.
#
# The txset.acquire `round.request` event attributes get no column either,
# and cannot: this Tempo (2.9.4, docker-compose.yml) queries them via
# event:name / event.<attr>, but a dedicated column accepts only
# scope: span or scope: resource -- never event. Those event filters
# therefore scan rather than index, which is fine for the per-span lookup
# they are used for; do not add an event-scoped column to the list below.
#
# The ledger_hash column below carries a second job as of the per-ledger
# trace join, which is why it stays the highest-value column here.
# Every span for one ledger -- ledger.acquire, consensus.validation.accept,
# ledger.validate, ledger.store -- now derives its TRACE ID from that same
# ledger hash, so the whole story of one slow ledger is one trace:
# {span.ledger_hash="<hash>"}
# returns all of them across the three threads that produced them. The
# column is what makes that lookup cheap; it also stays the way a reader
# confirms two spans really are the same ledger rather than a trace-id
# coincidence, since the attribute holds the full 32 bytes while the trace
# id is only the leading 16.
#
# validation_status and accept_gated get no column: both are small closed
# value sets promoted to spanmetrics dimensions instead (see the collector
# configs), so the aggregate question is answered by a metric query and no
# per-value trace lookup is needed.
parquet_dedicated_columns:
- name: ledger_hash
type: string
scope: span
- name: txset_hash
type: string
scope: span
- name: remote_endpoint
type: string
scope: span