Commit Graph

15842 Commits

Author SHA1 Message Date
Pratik Mankawde
056c863466 delete throwaway scripts
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-22 14:52:37 +01:00
Pratik Mankawde
3ad291eb75 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-22 14:44:21 +01:00
Pratik Mankawde
3a9dab6d7c Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-22 14:44:15 +01:00
Pratik Mankawde
644cf3a0a9 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-22 14:44:15 +01:00
Pratik Mankawde
531802ed81 Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-07-22 14:44:15 +01:00
Pratik Mankawde
12034f1a7f Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-07-22 14:44:15 +01:00
Pratik Mankawde
c608131e26 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-07-22 14:44:15 +01:00
Pratik Mankawde
032aa10d63 Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-07-22 14:44:15 +01:00
Pratik Mankawde
735e195005 Merge branch 'pratik/otel-phase2-rpc-tracing' into pratik/otel-phase3-tx-tracing 2026-07-22 14:44:15 +01:00
Pratik Mankawde
6f868e36e5 Merge branch 'pratik/otel-phase1c-rpc-integration' into pratik/otel-phase2-rpc-tracing 2026-07-22 14:44:15 +01:00
Pratik Mankawde
a25f18521e Merge branch 'pratik/otel-phase1b-telemetry-infra' into pratik/otel-phase1c-rpc-integration 2026-07-22 14:44:15 +01:00
Pratik Mankawde
64cea3ded4 docs(telemetry): use rpc_span::op::process constant in @code examples
The OTel naming check (Rule F) scans @code doc-comment examples and fails
on string-literal span names; Rule H warns on undefined SpanNames
constants. Replace the literal "subtask" and the undefined
rpc_span::op::dispatch with the defined rpc_span::op::process constant so
the examples model correct API usage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:43:59 +01:00
Pratik Mankawde
4535daa10d Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
Brings in the telemetry/metrics init-order fix (start before [rpc_startup]).

Conflict in Application.cpp: phase10 had reordered start() to run
telemetry+metrics first; phase9 relocated that block into a new
startTelemetry() called from setup() before the [rpc_startup] loop.
Resolved by taking the fix — the block lives only in startTelemetry()
(called once from setup(), after overlay_ is built), removed from start().
telemetry_->start() and metricsRegistry_->start() each appear exactly once.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:39:39 +01:00
Pratik Mankawde
93e95bdc03 fix(telemetry): start telemetry + metrics before [rpc_startup]
Metric-emitting code that first runs during ApplicationImp::setup() (the
[rpc_startup] loop) executed while the OTel meter was still empty, because
telemetry_ and metricsRegistry_ were started later in start(). A call-site
metric macro caches its instrument on first use via std::call_once, so that
first pre-meter use latched a null instrument for the process lifetime and the
metric silently never recorded (observed: rpc_in_flight_requests, emitted from
PerfLogImp::rpcStart, never appeared).

Extract telemetry_->start() and the metricsRegistry_->start() block into a new
private ApplicationImp::startTelemetry() and call it from setup() just before
the [rpc_startup] loop, so the meter is live before any metric-emitting code
runs. The call sits after overlay_ (and the other subsystems the observable-
gauge callbacks read) is constructed, since starting the metrics reader thread
earlier would let its callbacks call getOverlay() before overlay_ exists.
perfLog_->start() stays in start() — the macro call sites do not depend on it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:35:55 +01:00
Pratik Mankawde
7ef1f22ebe docs(telemetry): add Computation boundary to each panel description
Add a 'Computation boundary' section to every keyworded panel stating (a)
whether the result is per-node or aggregated across nodes, derived from
the query's grouping, and (b) where the value is computed along the
pipeline: xrpld code (MetricsRegistry OTel SDK, or beast::insight native),
the collector's SpanMetrics connector, or a Tempo TraceQL query over raw
spans. Classification is derived per panel from its actual queries and the
MetricsRegistry source, not guessed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:34:15 +01:00
Pratik Mankawde
8dd64d4dcd fix(telemetry): add second-scale spanmetrics histogram buckets
P95 of second-scale spans was a meaningless interpolation. The spanmetrics
histogram topped out at [.. 1s, 5s], so consensus.round (~3.9s) and
consensus.establish (~1.9s) all fell into one 1s-5s bucket and
histogram_quantile interpolated linearly across that 4s-wide gap — the
"Build vs Close" / "Ledger Close Duration" panels' P95 read ~4800ms purely
as an artifact (verified: sum/count avg = 3824ms). ledger.acquire was worse:
~17% of samples exceeded the 5s ceiling, so its p95/p99 were unmeasurable.

Add 2s, 3s, 4s (resolve the 1-5s pile-up) and 10s, 30s (give the
ledger.acquire catch-up tail a measurable home). All ten existing boundaries
are preserved and the list stays strictly ascending (the connector
binary-searches buckets and silently misbuckets otherwise). Pin unit=ms so a
future collector default-unit flip can't rename the metric to _seconds.

Buckets chosen from the live mainnet distribution, not guessed. Native
beast::insight histograms (ms-scale RPC/IO timers in Telemetry.cpp) are 100%
under 5s, so they keep the original buckets — this is collector-only.

Applies on collector restart (cumulative series reset once, handled by
rate()). Runbook and regression-threshold bucket notes updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:27:06 +01:00
Pratik Mankawde
03d04ea7b7 docs(telemetry): tag each keyword with per-node vs network-wide scope
Add a scope tag to every panel keyword — (per node), (network-wide),
(network event), or (cluster-wide) — so a reader can tell whether a term
describes this server's own state, a protocol-shared fact, or a
network-wide consensus process the node participates in. Add a matching
'Scope:' line to each glossary entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:21:34 +01:00
Pratik Mankawde
13a48cbbf2 refresh interval set to 30s
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-22 14:15:33 +01:00
Pratik Mankawde
62371de2a6 docs(telemetry): add panel Keywords + References and a telemetry glossary
Add a Keywords definition-list and a References link line to 178 Grafana
panel descriptions across all 14 dashboards, defining the XRPL/rippled
domain terms each panel uses (tiers 1-9: ledger, consensus, transaction
pipeline, fees/queue, node state, peer/overlay, storage, validator,
RPC/pathfinding). Cross-cutting chart terms and job-queue internals are
intentionally excluded.

Add docs/telemetry-glossary.md (86 terms, 9 categories) as the deeper
reference, linked from each panel's References line and from the runbook.
Keywords are injected only where a term appears in that panel's prose
(matched over description text, not source-file citations).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:14:12 +01:00
Pratik Mankawde
0e02a67e81 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-22 13:46:45 +01:00
Pratik Mankawde
4858f65be4 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-22 13:43:24 +01:00
Pratik Mankawde
091d3b2bb2 Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-07-22 13:43:24 +01:00
Pratik Mankawde
476963f1db Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-07-22 13:43:24 +01:00
Pratik Mankawde
23a0d70d49 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-07-22 13:43:24 +01:00
Pratik Mankawde
f59e34192a Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-22 13:43:24 +01:00
Pratik Mankawde
d64b744540 docs(telemetry): InboundLedger acquireSpan_ is thread-free, not detached
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:43:12 +01:00
Pratik Mankawde
b0b174b94d docs(telemetry): RCLConsensus roundSpan_ is thread-free, not detached
The roundSpan_ / roundSpanContext_ comments still described the old
'detached, Scope stripped' model. roundSpan_ is now a thread-free SpanGuard
(no Scope); children link via the captured roundSpanContext_.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:43:07 +01:00
Pratik Mankawde
5150159ca2 refactor(telemetry): ledger.acquire uses thread-free SpanGuard (no detach)
acquireSpan_ is emplaced on the acquiring thread and reset() on a JtLedgerData
worker. SpanGuard is now thread-free (owns no thread-local Scope), so it can be
created here and destroyed on the worker with no scope to strip — dropping the
.detached() call the old scoped SpanGuard required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:30:50 +01:00
Pratik Mankawde
dd96d8ad34 Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-22 13:28:44 +01:00
Pratik Mankawde
dad2dc2acb Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-22 13:28:24 +01:00
Pratik Mankawde
cef7a8b16c Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics
# Conflicts:
#	OpenTelemetryPlan/09-data-collection-reference.md
2026-07-22 13:28:15 +01:00
Pratik Mankawde
ba1b693177 Merge branch 'pratik/otel-phase2-rpc-tracing' into pratik/otel-phase3-tx-tracing 2026-07-22 13:13:24 +01:00
Pratik Mankawde
30398ce2fe Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-07-22 13:13:24 +01:00
Pratik Mankawde
4998384247 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-07-22 13:13:24 +01:00
Pratik Mankawde
b769542283 Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-07-22 13:13:24 +01:00
Pratik Mankawde
2f627e8e8e docs(telemetry): 09-doc — pathfind.request parents to rpc.process, not rpc.command
Reflects the C1 fix: rpc.command.* stays unscoped (its dispatch wraps
doRipplePathFind which yields), so pathfind.request nests under rpc.process.
The request -> compute -> discover sub-tree nests correctly via ScopedSpanGuard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:12:55 +01:00
Pratik Mankawde
beb5b2dddc fix(telemetry): scope ledger.build so tx.apply nests under it
ledger.build was left as unscoped SpanGuard after the type split, so tx.apply
(created synchronously during applyTxs on the same JtAccept worker) no longer
nested under it. buildLedgerImpl runs synchronously with no yield, so
ScopedSpanGuard is safe and restores the ledger.build -> tx.apply edge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:11:53 +01:00
Pratik Mankawde
b1f1e30450 fix(telemetry): scope pathfind.request/compute so children nest
pathfind.request (PathFind.cpp) and pathfind.compute (PathRequest.cpp doUpdate)
were left as unscoped SpanGuard after the type split, so pathfind.compute and
pathfind.discover no longer nested under them. Both handlers run synchronously
with no coroutine yield, so ScopedSpanGuard is safe and restores the
request -> compute -> discover sub-tree. rpc.command.* stays unscoped (callMethod
wraps doRipplePathFind which holds across a yield), so pathfind.request parents
to rpc.process.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 13:10:21 +01:00
Pratik Mankawde
946491258f fix(telemetry): correct Ledger Close Duration on consensus-health dashboard
The "Ledger Close Duration" panel measured the consensus.ledger_close span
duration, which only wraps the sub-millisecond onClose() prologue — not the
ledger close. Repoint it to the consensus.round span (full round, open to
accept) so it reflects actual close time (~3-5s on mainnet). The consensus_mode
filter is preserved (consensus.round carries that attribute, verified live).

The sibling rate panels (Consensus Mode Over Time, Accept vs Close Rate,
Validation vs Close Rate) keep using consensus.ledger_close: a rate of that
span is a valid per-close event counter, only its duration was wrong.

Runbook updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 12:28:45 +01:00
Pratik Mankawde
f52673b6c1 feat(telemetry): correct ledger-close-time derivation on dashboards
The "ledger close time" was mis-derived and partly un-queryable:

- Build vs Close Duration derived close time from the consensus.ledger_close
  span, which only wraps the onClose() prologue (~0.8ms live) — not the close.
  Repoint the close series to consensus.round (full round, live P95 ~4.8s).
- The network close-time value (close_time) lived only as a span attribute,
  un-queryable in Prometheus and unfit as a spanmetrics label (monotonic
  timestamp -> unbounded cardinality). Expose it as last_close_time on the
  existing server_info observable gauge (native gauge, no new instrument).
- Add a "Ledger Close Interval & Age" panel to ledger-operations and
  node-health: interval = 1/rate(ledgers_closed_total) (counter-based,
  scrape-independent); age = time() - (last_close_time + epoch_offset).

A gauge delta is deliberately NOT used for the interval — a timestamp gauge's
delta aliases to the scrape period, not the close cadence (verified live).
Guardrail comments in both collector configs record why close_time must never
become a spanmetrics dimension. Docs (09-reference) and the operator runbook
updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 12:23:21 +01:00
Pratik Mankawde
f78bc433b0 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-22 10:58:55 +01:00
Pratik Mankawde
eec3062c9c Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-07-22 10:58:50 +01:00
Pratik Mankawde
7bdc14eee5 docs(telemetry): 09-doc — deterministic roots are true roots; rootSpan->freshRoot
Document that deterministic-trace_id spans (tx.* apply pipeline, tx.process,
tx.receive, consensus.round) are now genuine trace roots with empty
parent_span_id via the custom DeterministicIdGenerator, superseding the old
synthetic-parent behavior that showed 'root span not yet received' in Tempo.
Also update the fresh-root note: peer entry spans use ScopedSpanGuard::freshRoot().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 10:58:35 +01:00
Pratik Mankawde
9725f5b48f fix(telemetry): phase-6 peer.proposal/validation.receive use ScopedSpanGuard::freshRoot
These peer-level entry spans (introduced on phase-6) used the removed
SpanGuard::rootSpan(). They are scoped on the peer thread and end there, so
use ScopedSpanGuard::freshRoot() — a scoped fresh trace root that does not
inherit any span left active on the peer thread.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 10:56:47 +01:00
Pratik Mankawde
6c21cc4af5 Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd
# Conflicts:
#	src/xrpld/overlay/detail/PeerImp.cpp
2026-07-22 10:53:58 +01:00
Pratik Mankawde
b2d6f06a9f Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-07-21 22:14:36 +01:00
Pratik Mankawde
7fc145ebd2 refactor(telemetry): consensus + peer-receive spans use spanContext()/freshRoot, drop detach
With unscoped SpanGuard + spanContext() (own-span capture), the consensus
round/establish/accept sites just capture and drop the detach dance;
openSpan + peer proposal/validation receive are thread-free handoffs (no
detach); rootSpan->freshRoot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 22:09:36 +01:00
Pratik Mankawde
cc7585c0a8 Merge branch 'pratik/otel-phase2-rpc-tracing' into pratik/otel-phase3-tx-tracing 2026-07-21 21:57:35 +01:00
Pratik Mankawde
30ee25a28b Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-07-21 21:57:35 +01:00
Pratik Mankawde
64a3c93188 test(telemetry): SpanGuardFactory uses spanContext() (captureContext renamed)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 21:57:22 +01:00