docs(telemetry): align runbook and plan docs with the shipped phase-9/10 code

The reference docs had drifted from the code in ways that break the reader
rather than merely misinform: PromQL examples that return no data, a rollback
flag that is a no-op, a sampling knob that does not exist, and two span parents
that moved. Code is treated as the truth throughout; where the code is the
defective side, the doc now records it as a known issue instead of describing
the bug as intent.

Renames the docs missed: histogram names gain the exporter's unit suffix
(ios_latency_milliseconds_bucket and four siblings), ledger_history_mismatch
gains _total, the StatsD-era quantile label gives way to le buckets,
rpc.request becomes rpc.http_request, traces_spanmetrics_calls_total becomes
span_calls_total, and the nine dotted xrpl.* span attributes are recorded as
renamed rather than left as live keys.

Re-parenting: consensus.update_positions and consensus.check are children of
consensus.establish, not of consensus.round.

Units and labels: state_accounting_*_duration is microseconds, not seconds;
cache_metrics label values are case-sensitive; object_count carries demangled
C++ type names. Nodestore read and write latency stays microseconds -- the
nanosecond accumulator change did not move the exported unit.

Adds what shipped but was undocumented: the ledger.acquire span, seven
consensus.round events, twelve span attributes, node_writes_duration_us, the
7-day validation-agreement window, the TxQ admission and reduce-relay metric
families, metrics_endpoint, and the phase-10 validation workflow.

Corrects claims that never held: 10% head sampling (it is fixed at 100%),
configurable redaction (it is unconditional), -DXRPL_ENABLE_TELEMETRY=OFF
(the flag is -Dtelemetry=OFF, default ON), FindOpenTelemetry.cmake and the
xrpl_telemetry target (neither exists), Promtail and a StatsD exporter in the
pipeline (neither exists), and Loki stream selection on job= (only
service_name is a stream label).

Phase 9 is marked complete, its provisioned alerting is attributed to the
branch that shipped it, and Phase 11 stays at zero except the one prerequisite
its code closes. Counts are reconciled repo-wide: 41 emitted span families,
15 dashboards on disk with 14 asserted, 13 alert rules in 5 groups.

Hardens the gate that let this drift through: Rule E of the naming check now
covers the reference docs, its allow-dotted marker is key-scoped and warns on
stale or empty use, a missing checked file is reported instead of silently
skipped, the test suite runs in CI, and doc paths trigger the check.

C++ and CMake changes are comment-only: three MetricsRegistry instrument names,
eight OTelCollector claims of a metric-name prefix that formatName never adds,
and the telemetry option's inverted default.
This commit is contained in:
Pratik Mankawde
2026-08-13 16:18:47 +01:00
parent 733af97ce3
commit 3153f3ef56
35 changed files with 4598 additions and 1390 deletions

View File

@@ -58,7 +58,7 @@ namespace beast::insight {
* @code
* auto collector = beast::insight::OTelCollector::New(
* "http://localhost:4318/v1/metrics", // OTLP/HTTP endpoint
* "xrpld", // metric name prefix
* "xrpld", // logging label only
* "node-1", // service.instance.id
* "xrpld", // service.name
* "mainnet", // xrpl.network.type
@@ -105,8 +105,12 @@ public:
*
* @param endpoint OTLP/HTTP metrics endpoint URL
* (e.g. "http://localhost:4318/v1/metrics").
* @param prefix Prefix prepended to all metric names
* (e.g. "xrpld").
* @param prefix Label for the collector's startup log line
* (e.g. "xrpld"). Exported metric names are produced
* by formatName(), which lowercases the raw name and
* maps dots and spaces to underscores. The service is
* identified by the `service.name` OTel resource
* attribute.
* @param instanceId Unique identifier for this node instance,
* emitted as the `service.instance.id` OTel
* resource attribute. Defaults to empty string

View File

@@ -95,9 +95,16 @@ message TMPublicKey {
// Older peers that do not understand field 1001 will simply ignore it
// per protobuf wire-format rules, preserving backwards compatibility.
//
// trace_state is reserved for future use (secure tracing pipeline,
// OpenTelemetryPlan/secure-OTel.md). It is currently neither populated
// on inject nor read on extract; consumers must not rely on it.
// trace_state (field 4) is reserved and inert: it is neither populated on
// inject nor read on extract, so consumers must not rely on it. Beyond the
// W3C tracestate use noted on the field below, it is the intended home for
// an authenticated token a receiver could verify before adopting a peer's
// trace context as its parent. Today this message is unauthenticated peer
// input: the receiver only checks that the ids are well formed (16-byte
// trace_id, 8-byte span_id, neither all-zero) and otherwise starts a fresh
// trace, so the ids are a hint, not trusted provenance. An authenticated
// scheme would need a shared verification key, a canonical form to sign,
// and a defined policy for peers that send no token.
message TraceContext {
optional bytes trace_id = 1; // 16-byte trace identifier
optional bytes span_id = 2; // 8-byte parent span identifier

View File

@@ -101,13 +101,23 @@ injectToProtobuf(opentelemetry::context::Context const& ctx, protocol::TraceCont
// Serialize flags
proto.set_trace_flags(spanCtx.trace_flags().flags());
// TODO(observability/secure-OTel): the protobuf TraceContext message
// also carries `trace_state` (field 4), which is currently neither
// populated here nor read by extractFromProtobuf above. The field is
// reserved for the secure tracing pipeline outlined in
// OpenTelemetryPlan/secure-OTel.md, where an authenticated token in
// tracestate will let receivers reject spoofed/poisoned trace context.
// Wire trace_state through inject/extract once the consumer lands.
/**
* TODO: wire `trace_state` (protobuf TraceContext field 4) through
* inject and extract. It is neither written here nor read by
* extractFromProtobuf above, so the field is inert on the wire.
*
* Two uses are intended. One is W3C tracestate vendor-specific
* key-value pairs, for cross-vendor propagation. The other is an
* authenticated token. Today a peer's trace context is
* unauthenticated input: extractFromProtobuf only checks that the ids
* are well formed (16-byte trace_id, 8-byte span_id, neither
* all-zero) before using them as a parent, so the ids are a hint
* rather than trusted provenance. A token the receiver could verify
* would let it decide whether to adopt a peer's context at all. That
* needs a shared verification key, a canonical form to sign, and a
* defined policy for peers that send no token. None of that exists
* yet, which is why the field stays unpopulated.
*/
}
} // namespace xrpl::telemetry