Commit Graph

593 Commits

Author SHA1 Message Date
Pratik Mankawde
bbc318fb6d Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
# Conflicts:
#	docker/telemetry/grafana/dashboards/ledger-data-sync.json
2026-07-24 21:03:26 +01:00
Pratik Mankawde
8f09dc2906 Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 21:02:43 +01:00
Pratik Mankawde
fe1c4db29c Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 21:02:39 +01:00
Pratik Mankawde
97ed918e16 fix(telemetry): Make overlay traffic bar-gauge labels readable
The bar labels on 'Overlay Traffic Heatmap (All Categories, Bytes In)'
were raw metric names carrying a redundant '_bytes_in' suffix, and the
half-width 8-row panel truncated both the category and the node
identity.

- Strip the '_bytes_in' suffix from the derived series label; the panel
  title already states the metric is inbound bytes.
- Widen the panel to full width and grow it to 12 rows so 20 bars render
  with their full category and node labels.
- Shift the Sync Diagnostics row and the panels below it down by 4 to
  keep the layout gap-free.
- Note the label derivation in the panel description.
2026-07-24 21:02:31 +01:00
Pratik Mankawde
ffeb82ab63 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
# Conflicts:
#	docker/telemetry/grafana/dashboards/node-health.json
2026-07-24 20:51:15 +01:00
Pratik Mankawde
9c54020322 fix(telemetry): plot all five states in State Duration Rate panel
The panel plotted only Full and Tracking, so the states a node actually
passes through while catching up were invisible. On the dev box's cold
sync the node spent ~19 minutes in Connected and ~3 seconds in Syncing,
while Tracking totalled 2 microseconds -- the one non-Full line the
panel did draw was the least informative of the five.

Add Syncing, Connected and Disconnected series (state-ladder order,
matching the Operating Mode Transitions panel) and rename the panel to
"State Duration Rate (All States)". Because the node is always in
exactly one state, the five rates sum to ~1.0, so the panel now reads as
"which state is time going into right now", and a handover between two
lines marks a state change with its width showing the dwell time.

Description expanded to the full section set (keywords, computation
boundary, references) used by the other panels on this dashboard.

Verified live: rate(state_accounting_connected_duration)/1e6 reaches
1.0 then 0.387 across the catch-up window and syncing reaches 0.0103 --
both previously undrawable.
2026-07-24 20:50:39 +01:00
Pratik Mankawde
3eae98fa85 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
# Conflicts:
#	docker/telemetry/grafana/dashboards/node-health.json
2026-07-24 20:45:29 +01:00
Pratik Mankawde
0d9533270a Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 20:44:27 +01:00
Pratik Mankawde
b0168f92a7 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 20:44:23 +01:00
Pratik Mankawde
a80cccb05a feat(telemetry): add Node Health verdict panel to Node Health dashboard
The dashboard showed 54 individual signals but no single answer to
"is this node healthy and doing its job?". A reader had to correlate
server state, ledger age and peer counts by eye.

Add a stat panel at the top that reduces the two conditions that define
a healthy observer node to one green/red verdict:

  server_state == 4 (Full)  AND  validated_ledger_age < 30s

Both terms use `== bool` so each yields 0/1, joined with
`* on(service_instance_id)` so the verdict is per node. Value mappings
render 1 as "Healthy" (green) and 0 as "Not Healthy" (red) with
background colouring, so the state is readable at a glance.

Placed at y=0 per the dashboard convention that gauges/stats lead;
existing panels shift down by 4 rows with no other change.

Verified live against Grafana Cloud: returns 1 for aws-dev-xrpl-1
(Full, validated seq 105,824,596).
2026-07-24 20:44:23 +01:00
Pratik Mankawde
a30c08240b fix(telemetry): drop xrpl_work_item from Sync Diagnostics sum-by clauses
The four aggregated Sync Diagnostics panels grouped by xrpl_work_item,
which no layer in this repo emits (it is injected by the perf-iac
harness). That tripped Rule D of the telemetry naming check:

  D  ledger-data-sync.json  xrpl_work_item
     must exist in L1, a metric label, or be a builtin

Align with the convention used by every other aggregated panel in the
dashboard set: group by (service_instance_id, xrpl_branch,
xrpl_node_role) and leave the xrpl_ident label_join untouched. The
legend is unaffected -- label_join over a label dropped by the
aggregation contributes an empty segment, which the trailing
label_replace already strips.

Verified live: both the NuDB ratio and the job-queue p95 queries still
return per-node series rendering as "[aws-dev-xrpl-1]".
2026-07-24 20:44:13 +01:00
Pratik Mankawde
6cd2d3f280 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-24 19:57:13 +01:00
Pratik Mankawde
75cc3785ad Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 19:57:13 +01:00
Pratik Mankawde
63474c510d Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 19:57:13 +01:00
Pratik Mankawde
5533dde43d fix(telemetry): Sync State axis label "State (0-4)" -> "Server State"
The 0-4 values now render as named states via value mappings, so the numeric
axis label is misleading. Rename to "Server State".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 19:57:11 +01:00
Pratik Mankawde
5bc49683a5 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-24 19:51:37 +01:00
Pratik Mankawde
5718ebbdd6 Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 19:51:37 +01:00
Pratik Mankawde
8f8ce40a21 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 19:51:36 +01:00
Pratik Mankawde
ecfaab9f85 feat(telemetry): map Sync State 0-4 to named states with threshold colors
Add value mappings (0 Disconnected, 1 Connected, 2 Syncing, 3 Tracking,
4 Full) and matching red->green thresholds to the Sync State panel, so the
line, tooltip, and legend render state names and colors instead of bare 0-4.
Keeps the minimal custom-key convention; only the Sync State panel changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 19:51:25 +01:00
Pratik Mankawde
cab0bc4f7d Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-24 19:26:23 +01:00
Pratik Mankawde
3c9935c0df Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 19:26:14 +01:00
Pratik Mankawde
e8aac409be Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 19:26:06 +01:00
Pratik Mankawde
794b5f43eb style(telemetry): align Sync Diagnostics legends with dashboard xrpl_ident format
Rework the 10 Sync Diagnostics panels' legends to match the format used by the
existing panels: wrap each query in label_join + label_replace to build the
xrpl_ident label ([service_instance_id, xrpl_branch, xrpl_work_item] with empty
values stripped) and set displayName to "${series} ${xrpl_ident}". Verified
against a live node: renders as "Series [aws-dev-xrpl-1]" with no empty-label
gaps, identical mechanism to the original 15 panels. Only the new panels change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 19:25:54 +01:00
Pratik Mankawde
c1dcb9b218 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
# Conflicts:
#	docker/telemetry/grafana/dashboards/ledger-data-sync.json
2026-07-24 18:57:07 +01:00
Pratik Mankawde
c7243b57b5 Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-24 18:54:59 +01:00
Pratik Mankawde
c0daf55f59 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-24 18:54:52 +01:00
Pratik Mankawde
eba21104c0 feat(telemetry): add Sync Diagnostics panels to Ledger Data & Sync dashboard
Add a 10-panel "Sync Diagnostics" row that shows ledger-sync slowdown and its
causes, laid out top-to-bottom as symptom -> latency -> root cause:

- Red flags: Sync State, Validated Ledger Age, Ledger Close Rate
- Latency: Job Queue Wait p95 by type, NuDB Read Latency, I/O Scheduler p95
- Root cause: NuDB Cache Hit Ratio, NuDB Read Pressure, Job Queue Depth,
  Load Factor & Peers

All panels use native beast::insight metrics introduced on this branch
(nodestore_state, ledgermaster_*, jobq_*_q, ios_latency, load_factor_metrics,
peer_finder_*) plus the consensus.mode_change span metric. Queries filter by
the dashboard's $node and tier variables and were verified against a live
node. Nodestore ratio panels use sum-by(identity) matching to bridge the
metric= sub-label.

Format matches the dashboard convention: minimal custom keys, ${DS_PROMETHEUS}
datasource uid, and the standard What/How/Reading/Healthy/Watch/Source/Function
description structure. Pure-append; existing panels untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 18:53:53 +01:00
Pratik Mankawde
f547c80f4c fix(telemetry): mirror second-scale histogram buckets into Alloy config
The Alloy spanmetrics connector (perf-iac nodes run Alloy instead of the
collector-contrib image) carried the same old [.. 1s, 5s] bucket list, whose
buckets are documented as "copied from" the collector config. Sync it to the
15-bucket layout (adds 2s, 3s, 4s, 10s, 30s) so Alloy-fed nodes get the same
accurate second-scale consensus and ledger.acquire percentiles as
collector-fed nodes. unit was already "ms". Kept strictly ascending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 14:05:37 +01:00
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
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
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
1f98f2c46a test(telemetry): add rpc_in_flight_requests to phase10 expected_metrics harness inventory 2026-07-21 20:35:12 +01:00
Pratik Mankawde
c715f561f3 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation
# Conflicts:
#	src/xrpld/telemetry/MetricsRegistry.h
#	src/xrpld/telemetry/ValidationTracker.h
2026-07-20 18:05:24 +01:00
Pratik Mankawde
02ead706b3 feat(telemetry): Node Health Server Info panels + ledger-seq descriptions
Sync the Node Health dashboard with panels and field settings refined in
Grafana, and document the ledger-convergence panels:

- Add descriptions for "Validated Ledger Seq — Current (Stat)" (per-node lag
  behind the network tip) and "Validated Ledger Seq — Convergence (Max − Min)"
  (seq spread across nodes), in the standard 7-field panel format.
- Peer Count: threshold colours (red < 5, yellow < 10, green >= 10) so a low
  peer count reads red rather than using a value gradient.
- Minor field-config fixes on Last Close and NuDB Storage panels (axis label,
  threshold cleanup) as adjusted in Grafana.

Add the Grafana duration unit "dthms" to the cspell dictionary. Panel content
stays at parity with the Grafana Cloud copy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:55:30 +01:00
Pratik Mankawde
36e3025ab4 fix(telemetry): re-layout Node Health into subsystem rows
Regroup all 47 panels under correct subsystem rows and fix the broken row
structure. Previously the "NodeStore I/O" row had no gridPos and collided at
y=32 with an appended "Extended Metrics" catch-all row, so NodeStore I/O
rendered empty and its panels landed under the wrong header.

- Rows: Overview (top), Operating Mode, NodeStore I/O, Jobs, Caches, Server
  Info, Complete Ledgers & DB, Ledger Economy. Drop the stray "Extended
  Metrics" row; each panel now sits under its subsystem.
- Normalize panel heights to three buckets: 12 (standard), 16 (emphasis /
  detail plots), 24 (Operating Mode state timeline). Widths stay half (12) or
  full (24).
- Contiguous, non-overlapping gridPos; all 47 panels preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 13:16:01 +01:00
Pratik Mankawde
0d704f748a fix(telemetry): comma-format legend identity + plain-text dashboard descriptions
Rework the legend identity bracket across all 14 dashboards so it reads
"<series> [instance, branch, work_item]" (comma-separated, Node Role dropped)
and collapses cleanly when perf-iac labels are absent -- "<series> [instance]"
with no empty "[, ]" gaps.

- Build one xrpl_ident label per query via label_join + a single label_replace
  that trims leading/trailing empty segments and brackets the result. Done at
  the outermost (post-aggregation) level so it survives each panel's by() clause.
- Add service_instance_id to the by() of 6 panels that grouped only by node_role,
  so same-branch validator/peer series stay distinguishable after dropping the
  node_role legend token.
- Fold the two legendFormat two-bracket panels (Transaction Results by Type,
  Tx Apply Pipeline Latency by Type and Stage) into the same single-bracket form.
- Rename the annotation query label "Perf runs (perf-iac)" to
  "Annotate perf-iac runs".
- Revert dashboard-level descriptions to plain text (the folder-list info tooltip
  escapes HTML, so <br>/markdown render literally).

Verified: output byte-identical to the prior multi-call cleanup over a 2-day
live perf window; all 14 files valid JSON.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 12:05:50 +01:00
Pratik Mankawde
48c97432be dashboards updated with proper legends
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-15 18:07:28 +01:00
Pratik Mankawde
216a9c6c1b added annotations section to dashboards
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-07-15 13:36:38 +01:00
Pratik Mankawde
1406c50e3d Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-07-15 11:45:46 +01:00
Pratik Mankawde
49e44259f7 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-15 11:45:46 +01:00
Pratik Mankawde
352c85d945 fix(telemetry): wrap legend identity labels in a single bracket
Group the node + perf-iac identity labels inside one pair of brackets in the
legend Display name so a series reads e.g. "Queue Depth [validator-0
test:pr:abc123 validator RIPD-7455]" on a perf node and "Queue Depth
[aws-dev-xrpl-1]" on a plain node. Absent perf-iac labels collapse to a single
space before the closing bracket; no empty "[]", no data impact. Covers the
eleven dashboards this branch owns.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:45:26 +01:00
Pratik Mankawde
9e914c08be fix(telemetry): wrap legend identity labels in a single bracket
Group the node + perf-iac identity labels inside one pair of brackets in the
legend Display name:
  ${__field.labels.series} [${__field.labels.service_instance_id} ${__field.labels.xrpl_branch} ${__field.labels.xrpl_node_role} ${__field.labels.xrpl_work_item}]
so a series reads e.g. "Queue Depth [validator-0 test:pr:abc123 validator
RIPD-7455]" on a perf node and "Queue Depth [aws-dev-xrpl-1]" on a plain node.

Absent perf-iac labels render empty and collapse to a single space before the
closing bracket (HTML/SVG whitespace collapse) — the only cosmetic artifact on
non-perf nodes; no empty "[]" and no data impact. Verified on a live local
Grafana render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:45:15 +01:00
Pratik Mankawde
e08b29016d Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-07-15 11:33:32 +01:00
Pratik Mankawde
d764238474 Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill 2026-07-15 11:33:26 +01:00
Pratik Mankawde
e3452f9e30 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation
# Conflicts:
#	docker/telemetry/otel-collector-config.yaml
2026-07-15 11:33:24 +01:00