Commit Graph

15675 Commits

Author SHA1 Message Date
Pratik Mankawde
24cebcc22d Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-17 11:37:34 +01:00
Pratik Mankawde
7ff124fac3 fix(telemetry): allowlist xrpl_work_item as an external infra label
check-otel-naming fails Rule D on this branch: ledger-data-sync.json
aggregates by xrpl_work_item, which nothing in-tree emits because
perf-iac's alloy pipeline stamps it, so it cannot be derived from
*SpanNames.h. The sibling perf-iac identities xrpl_branch and
xrpl_node_role are already allowlisted; this one was missed when the
by() clauses were reintroduced.

Add it to EXTERNAL_INFRA_LABELS alongside them. Verified by removing
the entry again, which restores the failure.
2026-08-17 11:37:25 +01:00
Pratik Mankawde
a09416eddc Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-15 17:49:18 +01:00
Pratik Mankawde
a61c349712 fix(telemetry): switch sample config to server=otel
This branch removes the collector's StatsD receiver and un-publishes
8125/udp, but xrpld-telemetry.cfg still selected server=statsd, so the
sample config sent beast::insight metrics over UDP to a port nothing
listens on. Phase7_taskList.md:132 lists this switch as required work.

Select server=otel and replace address= with the OTLP metrics endpoint.
Document that endpoint and prefix are informational only, since
OTelCollector records on the global MeterProvider that [telemetry]
configures and formatName() applies no prefix, and note that beast
instruments are not exported yet because the collector is constructed
before the MeterProvider is registered.
2026-08-15 17:48:44 +01:00
Pratik Mankawde
d4282cc36e fix(telemetry): correct log-correlation defects found in PR review
Six findings from the review of #6494 survived independent verification.
Each was checked against the branch tip, and where behaviour was in
question, against a live collector and Loki rather than from the
reviewer's claim or from documentation alone.

Plan-doc section numbering. 06-implementation-phases.md used "## 6.9"
twice: for the new Phase 8 section and for the pre-existing Risk
Assessment. Three references already pointed at 6.8.1 and none at 6.9,
and the later phases are numbered 6.8.2 through 6.8.4, so Phase 8
becomes 6.8.1 and the sequence is monotonic. Renumbering to 6.10, as
suggested on the PR, would have collided with Success Metrics.

filelog read position. The receiver relied on the upstream default
start_at=end, which skips everything a node wrote before the first poll
and reads nothing at all from a log that has stopped being written to.
Read from the beginning instead, paired with a file_storage extension so
a restart resumes at the last offset rather than re-ingesting the file.
The collector image runs as 10001:10001 and ships no writable directory,
and a fresh named volume is root-owned, so a one-shot init service
prepares the volume first. It reuses an image the stack already pulls,
adding no new dependency.

Loki log stream label. The job resource attribute did not become a Loki
index label, so the documented {job="xrpld"} queries matched nothing.
Verified against grafana/loki:3.4.2 with its default config: only
service_name and deployment_environment are indexed, and job arrives as
structured metadata, which a stream selector cannot match. Dropped the
attribute and moved the twelve queries this branch introduced to
{service_name="xrpld"}. Three further occurrences in
07-observability-backends.md originate on the phase-1a branch and are
left for a commit there.

Trace ids on unsampled spans. Logs::format emitted trace_id and span_id
whenever the span context was valid. A span dropped by the
ParentBasedSampler still carries its parent's ids, so log lines
advertised traces that were never exported and the log-to-trace link
resolved to nothing. Require the sampled flag as well, and correct the
task list and the documentation that promised the fields unconditionally.

The remaining two findings were refuted. The reported risk of signing
material reaching Loki does not hold: Logs::format already scrubs seven
sensitive fields, and there is a single write path to the log file, so
every JLOG site is covered. The suggestion to add internalLink to the
Loki derived field is not applicable, because that key is not part of
Grafana's schema.
2026-08-15 17:32:57 +01:00
Pratik Mankawde
87fc9eaee6 Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-08-14 22:59:12 +01:00
Pratik Mankawde
efd51f50d4 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-14 22:59:12 +01:00
Pratik Mankawde
773a5cc0fb fix(telemetry): stop the dashboard lint passing when it checked nothing
Run with no arguments the script iterated an empty list, found no
violations and printed "OK: 0 dashboard(s) passed" with exit 0 -- a clean
bill of health for reading no files, indistinguishable from a real pass.

A bare run now defaults to every dashboard beside the script, and a run
that still ends up with nothing to check exits 2 rather than reporting
success. Passing paths explicitly behaves as before.
2026-08-14 22:58:58 +01:00
Pratik Mankawde
292aee922a Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-14 21:47:42 +01:00
Pratik Mankawde
004b8e92ab fix(telemetry): keep the work item in ledger-data-sync aggregations
Nine targets across four panels filtered on xrpl_work_item while leaving
it out of their sum by() grouping. PromQL keeps only the labels listed in
by(), so the label was dropped from the result and the xrpl_ident legend
these panels build from it lost that segment.

Perf-iac runs stamp xrpl_work_item and give each work item its own set of
nodes, so service_instance_id already separates the runs; the visible
effect is the legend rather than merged series. Adding the label makes the
work item identifiable, which is the comparison these panels exist for.

NuDB Read Latency and NuDB Read Found Ratio each divide two aggregations.
Both sides get the label so their label sets stay equal and vector
matching still works.
2026-08-14 21:47:20 +01:00
Pratik Mankawde
46ed205790 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-14 21:21:28 +01:00
Pratik Mankawde
be8f987b39 docs(telemetry): drop the phase number from a node-health row title
The row was titled after the rollout phase its metrics came from, a number
defined only in a planning folder outside the shipped tree. Grafana shows
this title to operators, so it named something no reader could look up.
2026-08-14 21:21:25 +01:00
Pratik Mankawde
3a91a7414e Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics
# Conflicts:
#	docker/telemetry/grafana/dashboards/statsd-rpc-pathfinding.json
#	docker/telemetry/integration-test.sh
2026-08-14 21:20:39 +01:00
Pratik Mankawde
974835589a docs(telemetry): drop the plan task reference from a StatsD panel note
Two panel descriptions pointed at a rollout phase and task number defined
only in a planning folder outside the shipped tree. The note still names
the file and the change it is waiting on, which is the part a reader can
act on.
2026-08-14 21:19:49 +01:00
Pratik Mankawde
143436edbf Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-08-14 21:18:05 +01:00
Pratik Mankawde
8670e31d6c docs(telemetry): drop rollout phase numbers from the span catalog
The catalog tagged every span with a rollout phase number defined only in
a planning folder outside the shipped tree, so the column meant nothing
to a reader of the repository. The span name and source file identify
each entry.
2026-08-14 21:17:02 +01:00
Pratik Mankawde
4e9b844cc1 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-08-14 21:15:20 +01:00
Pratik Mankawde
68b94e625c docs(telemetry): name log-trace correlation instead of its phase number
These comments and headings identified the feature by a rollout phase
number defined only in a planning folder outside the shipped tree, so the
label meant nothing to a reader of the repository.
2026-08-14 21:13:59 +01:00
Pratik Mankawde
3d6c2b2948 Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-08-14 21:12:34 +01:00
Pratik Mankawde
2bac88e67c test(telemetry): label integration-test sections by what they verify
The section labels carried rollout phase numbers that are defined only in
a planning folder outside the shipped tree, so they meant nothing to a
reader of the repository. The descriptive half of each label already
identifies the section.
2026-08-14 21:11:54 +01:00
Pratik Mankawde
c4888dd066 test(telemetry): label the native-metrics section by what it verifies
The label carried a rollout phase number defined only in a planning
folder outside the shipped tree. The descriptive half already identifies
the section.
2026-08-14 21:11:14 +01:00
Pratik Mankawde
6ac68abfb5 docs(telemetry): drop plan-document pointers from consensus tracing comments
These comments pointed at a planning folder and at its rollout phase
numbering, neither of which is part of the shipped tree, so the
references would dangle for any reader of the repository. Each comment
now states the fact it was pointing at.
2026-08-14 21:11:07 +01:00
Pratik Mankawde
4ebf780868 docs(telemetry): drop the plan-folder pointer from the trace_state note
The trace_state comment pointed at a planning document that is not part
of the shipped tree, so the reference would dangle for any reader of the
repository. State the reserved-and-inert fact on its own.
2026-08-14 21:10:26 +01:00
Pratik Mankawde
91fd4d3532 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 14:36:20 +01:00
Pratik Mankawde
b0ae15ad8c Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-08-07 14:36:20 +01:00
Pratik Mankawde
63173d2703 Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-08-07 14:36:19 +01:00
Pratik Mankawde
8e3b0735a2 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-08-07 14:35:28 +01:00
Pratik Mankawde
2e21758a49 Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-08-07 14:35:28 +01:00
Pratik Mankawde
05335fa3e3 Merge branch 'pratik/otel-phase2-rpc-tracing' into pratik/otel-phase3-tx-tracing 2026-08-07 14:35:28 +01:00
Pratik Mankawde
b47d4f94fd Merge branch 'pratik/otel-phase1c-rpc-integration' into pratik/otel-phase2-rpc-tracing 2026-08-07 14:35:28 +01:00
Pratik Mankawde
379f4ff60b Merge branch 'pratik/otel-phase1b-telemetry-infra' into pratik/otel-phase1c-rpc-integration 2026-08-07 14:34:47 +01:00
Pratik Mankawde
71d1338313 Merge branch 'pratik/otel-phase1a-plan-docs' into pratik/otel-phase1b-telemetry-infra 2026-08-07 14:34:39 +01:00
Pratik Mankawde
ca13447ac5 Merge branch 'develop' into pratik/otel-phase1a-plan-docs 2026-08-07 14:34:00 +01:00
Pratik Mankawde
e9ce861add Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 12:54:35 +01:00
Pratik Mankawde
97089a3b6f fix(telemetry): stop repeating panels stranding their neighbours
A repeating panel expands into one copy per network at view time and, with
maxPerRow=2, claims the whole row. The non-repeating panel paired beside it was
pushed to the next line but kept its stored x=12, so it rendered on the right
against an empty gap.

Two changes to how the layout is planned:
  - a repeating panel gets a row to itself. It keeps w=12, so its copies still
    tile two across inside that row.
  - single-value panels are grouped to the top of each row section, so the
    charts that follow pair with each other instead of being split up by an
    interleaved repeat. Without this the gaps just become wasted half-rows.

Verified per dashboard: no panel lost, every targets block byte-identical, ids
1..N, no overlaps, and no row left with a gap on its left.
2026-08-07 12:54:25 +01:00
Pratik Mankawde
76d440aa40 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 12:38:46 +01:00
Pratik Mankawde
e84b9aada0 fix(telemetry): give heatmap panels the options the plugin requires
Every heatmap carried only `tooltip` and `yAxis`, missing `calculate`, `color`
and `cellGap`. Grafana's heatmap plugin treats those as required, and without
them the panel fails to initialise: the dashboard opens with "An error occurred
within the plugin" rather than a chart.

The option values are taken from the one heatmap in this stack that does render
on Grafana Cloud (ledger-sync-health): calculate=false since the queries already
return histogram buckets, the Turbo 64-step scheme, and cellGap=1. Each panel
keeps its own yAxis label, unit and tooltip settings.

This is a long-standing defect rather than fallout from the recent layout work -
the same options are absent in origin/phase9 and in the cloud copies that were
already live.
2026-08-07 12:36:22 +01:00
Pratik Mankawde
a1919a0233 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 12:26:01 +01:00
Pratik Mankawde
b226a34be4 fix(telemetry): taller panels, and stop repeating timeline and heatmap panels
Two problems showed up once these dashboards were live on Grafana Cloud.

Panels were too short. Charts at h=8 clipped their legends mid-row, and stats
at h=4 were cramped. Every visualisation is now h=10, with tables and logs at
h=12; the log-derived-insights instruction banner keeps h=12 for its prose.
Uniform height also means any two panels can pair side by side.

Repeat on a state-timeline broke the dashboard outright: ledger-data-sync
failed to open on Cloud at v45 and had to be restored to v44. Repeat is now
limited to single-value panels (stat, gauge, bargauge, table). Charts show
their networks as separate series instead, which is what a chart is for.

Repeat was also sticky: normalization only ever added the keys, so a panel that
picked them up in an earlier pass kept them even after its type stopped being
eligible. The keys and the title suffix are now removed from ineligible panels,
which is what actually cleared the two timeline panels here.

Verified per dashboard: no panel lost, every targets block byte-identical, ids
1..N, no grid overlaps, and repeat present only on stat/gauge/bargauge.
2026-08-07 12:25:50 +01:00
Pratik Mankawde
e477ca8a6c Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 11:54:57 +01:00
Pratik Mankawde
d5763420f9 style(telemetry): lead each dashboard row with its single-value panels
Guideline 8 asks for gauges and stats at the top. Seven dashboards had them
scattered below charts, so the reader met a wall of time series before the
at-a-glance numbers that give those series context.

Stats, gauges and bar gauges now come first within each row section. The move
is deliberately scoped to inside a section: shifting a panel across a row
boundary would change which category it belongs to. Panels keep their relative
order otherwise, so the reading sequence within each group is unchanged.

Whole panel objects are cut and re-spliced as raw text, so their contents stay
byte-identical and only gridPos and id are recomputed. Verified per dashboard:
panel count unchanged, no panel lost, every targets block byte-identical, ids
still 1..N, and no row section left with a stat below a chart.
2026-08-07 11:54:48 +01:00
Pratik Mankawde
0fc2844d40 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-07 11:32:13 +01:00
Pratik Mankawde
1d5697d7d3 style(telemetry): uniform dashboard layout, stable panel ids, row grouping
These dashboards were hand-authored over time and had drifted apart: panel
heights spanned ten different values, nine dashboards had no row grouping,
line-chart styling was inconsistent, and no panel carried an id, so Grafana
assigned them positionally at load and every panelId deep link was only as
stable as the panel order.

Per panel, in document order:
  - id           written as 1..N so panelId links address a specific panel
  - gridPos      quantized to at most two panels across: charts h=8,
                 stats/gauges h=4, tables/logs h=12 full width. Panels are
                 paired only with an equal-height neighbour, so no row is left
                 with a ragged half-empty cell.
  - line charts  lineWidth=1, fillOpacity=0, pointSize=5, gradientMode=none
  - repeat       xrpl_network_type (horizontal, maxPerRow=2) with a
                 [$xrpl_network_type] title suffix, on the panel types where
                 overlaying two networks in one panel reads as noise
                 (stat/gauge/bargauge/table/state-timeline). Line charts keep
                 their networks as separate series, which is the point of a
                 line chart.
  - decimals     0 where the value counts discrete things (threads, peers,
                 queue depths); a fractional thread count is meaningless.
  - rows         category rows added where a dashboard had none

Panels whose legend sits on the right stay full width: a side legend needs the
horizontal room, and squeezing it to half width clips the series names.

Edits were made as raw-text replacements, not a json.dump round-trip, so
formatting and escaping of untouched lines are byte-identical. Verified per
dashboard: panel count unchanged, every targets block byte-identical, all
descriptions unchanged, ids exactly 1..N, and no two panels overlapping on the
grid. The repo dashboard lint and the OTel naming check both pass.
2026-08-07 11:31:54 +01:00
Pratik Mankawde
3a889cf41f Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-08-06 21:23:15 +01:00
Pratik Mankawde
79a0193854 Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics
# Conflicts:
#	docker/telemetry/grafana/dashboards/transaction-overview.json
2026-08-06 21:22:49 +01:00
Pratik Mankawde
84ef8cbf33 fix(telemetry): drop unmeasurable Queue Bypass Ratio panel
The Transaction Overview panel "Queue Bypass Ratio (Direct Apply vs
Enqueue)" reported a confident 0.50 on every node while the true bypass
rate was zero. The two spans it divided are not disjoint alternatives:
txq.apply_direct is a child of txq.enqueue. TxQ.cpp creates the
apply_direct span as the first statement of tryDirectApply(), ahead of
the account, sequence and fee-level guards, and tryDirectApply() is
called from inside the live enqueue scope. The span therefore counts
attempts, so the denominator direct + enqueue counts each transaction
twice and pins the ratio to one half algebraically.

Measured on a four-node fleet: 6082443 direct against 6082877 enqueue
over the same population, panel output 0.5000170 on three nodes and
0.5000000 on the fourth. Grouping txq.enqueue by txq_status over seven
days returns only "rejected" -- no transaction has ever taken the
direct-apply path.

Remove the panel rather than repoint it. A correct expression using
txq_status as the disjoint discriminator would render permanently
empty on this fleet, which reads no better than a wrong number.

Widen the band partner "TxQ Enqueue Rate by Transaction Type" from 12
to 24 columns so the y=48 band still fills the grid. Every band in all
ten dashboards sums to 24 columns; leaving a half-width hole would be
the only exception. Panel order and every other panel's position,
width and height are unchanged.

The runbook already listed txq.apply_direct as available but not
paneled, so that row becomes accurate. Rows describing the span itself
are untouched -- the span and its metric are unchanged.
2026-08-06 19:01:15 +01:00
Pratik Mankawde
ef05e1b2a1 fix(telemetry): filter zero denominators instead of clamping them
Panels 21 (NuDB Read Latency) and 23 (NuDB Read Found Ratio) on the
Ledger Data & Sync dashboard guarded their divisor with
clamp_min(<denominator>, 1). clamp_min raises the value, not just the
zero case, so any node reading fewer than 1 block per second was
divided by a fabricated 1 instead of by its real read count.

Replace the clamp with the filter (<denominator> > 0). A comparison
without the bool modifier drops the sample rather than rewriting it, so
these panels now show no data instead of a wrong number.

Measured over 7 days: five nodes fall below 1 read/s. On validator-0 the
clamp reported 2.726 us/read against a true 5.493, and on nonUNLmalloc-tc
it reported 0 us/read, which cannot occur. The error is largest exactly
when panel 21 is used as the bottleneck discriminator during a stall,
because that is when the read rate collapses toward zero.

Matches the existing idiom on the same nodestore_state metric family in
the NodeStore Write vs Read Latency panel.
2026-08-06 19:01:00 +01:00
Pratik Mankawde
110a60aa38 Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-08-06 14:28:37 +01:00
Pratik Mankawde
185d345c94 Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-08-06 14:28:31 +01:00
Pratik Mankawde
c2bfad857b Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-08-06 14:28:23 +01:00