Commit Graph

541 Commits

Author SHA1 Message Date
Pratik Mankawde
60f348e28d Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-18 09:34:50 +01:00
Pratik Mankawde
41140ec6d1 merge: bring the runbook attribute-row fix forward from phase-8
The table conflicted because both sides edited it: this branch had dropped
ledger_seq from the tx.apply row, and the incoming side updated the tx.receive
row. Kept both.
2026-09-18 09:34:19 +01:00
Pratik Mankawde
4ca5a21430 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-18 09:33:24 +01:00
Pratik Mankawde
673e12e7b3 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-09-18 09:33:24 +01:00
Pratik Mankawde
795c9ad39c Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-09-18 09:33:24 +01:00
Pratik Mankawde
3b60a190de fix(telemetry): drop the remaining suppressed dimensions and diagram values
Alloy and the Grafana Cloud collector still declared a spanmetrics dimension
for an attribute tx.receive no longer sets, which only widens the label set.
The runbook's drop-path diagram still listed two tx_status values that no
longer exist, because the paths that set them now run before the span starts.
2026-09-18 09:32:29 +01:00
Pratik Mankawde
675dffdc71 docs(telemetry): drop suppressed from the tx.receive attribute list
The span is created after the duplicate check, so it never carries the
attribute, and the row now says which transactions it covers.
2026-09-18 09:31:23 +01:00
Pratik Mankawde
e0520b7e46 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-17 17:02:27 +01:00
Pratik Mankawde
d0baef8c92 Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation 2026-09-17 17:01:21 +01:00
Pratik Mankawde
6220c211fe Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics 2026-09-17 17:01:20 +01:00
Pratik Mankawde
aea4431807 Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd 2026-09-17 17:01:20 +01:00
Pratik Mankawde
c1086e63a2 Merge branch 'pratik/otel-phase4-consensus-tracing' into pratik/otel-phase5-docs-deployment 2026-09-17 17:01:20 +01:00
Pratik Mankawde
de3e376944 Merge branch 'pratik/otel-phase3-tx-tracing' into pratik/otel-phase4-consensus-tracing 2026-09-17 17:01:20 +01:00
Pratik Mankawde
94bdd19608 Merge branch 'pratik/otel-phase2-rpc-tracing' into pratik/otel-phase3-tx-tracing 2026-09-17 17:01:20 +01:00
Pratik Mankawde
3c05bdfdd8 ci: call the telemetry validation from on-pr.yml
The validation owned its own push trigger and paths filter, which made it the one
build-and-test workflow outside the on-pr.yml plus reusable-*.yml pair the rest of
CI uses. Rename it to reusable-telemetry-validation.yml, take workflow_call, and
let on-pr.yml decide when it runs.

on-pr.yml gains a second changed-files list for the telemetry paths. Its existing
`go` flag is true for nearly every pull request, so gating on `go` alone would run
a self-hosted build and a 30-minute cluster on all of them.

The configure step no longer repeats the telemetry option. A command-line define
is written to the cache before the toolchain runs and wins over it, so it could
turn telemetry on with the package never fetched. build-xrpld reads the value the
build actually configured out of CMakeCache.txt and publishes it as a job output;
validate-telemetry runs only when that says telemetry is on, and every value CMake
does not accept as a boolean fails the job rather than skipping silently.
2026-09-17 16:55:56 +01:00
Pratik Mankawde
8cb8f6b6c6 build: drop the second telemetry default and its stale docs
This branch rewrote the CMakeLists telemetry block and the build doc. Both now
describe a CMake option that no longer exists: the Conan option is the switch and
the generated toolchain carries it into CMake. The comment also recorded the
state of the change rather than the behaviour of the code.

The doc's "Building without telemetry" section told readers to pass
-Dtelemetry=OFF to CMake as well, which would override the toolchain rather than
follow it.
2026-09-17 16:54:18 +01:00
Pratik Mankawde
e52f235356 build: make the Conan option the only telemetry switch
CMakeLists declared option(telemetry) with a default of its own, so the setting
had two homes and they were free to disagree. The Conan option already reaches
CMake without it: conanfile.py forwards the option into the generated toolchain,
which sets the variable this file reads, and every build here goes through Conan.

Drop the option() call and keep the if(telemetry) test. docs/build/telemetry.md
told readers a CMake option had to be set as well, so that goes with it.
2026-09-17 16:54:03 +01:00
Pratik Mankawde
5f03e41f83 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-16 13:46:34 +01:00
Pratik Mankawde
ec0bfe521d refactor(telemetry): move the metrics pipeline core into libxrpl
MetricsRegistry did two jobs. It owned the OTel metrics pipeline, and it
registered the observable gauges whose callbacks read live application
services. The second job is what made the whole class xrpld-tier, so the
pipeline's lifecycle -- the recording() gate and the stop() teardown that
closes a use-after-free window -- could not be unit-tested in xrpl_tests.

Split it in two:

- xrpl::telemetry::MetricsRegistry (libxrpl) owns the exporter, provider,
  meter, the 16 synchronous instruments, recording(), stop(), and the
  record*/increment* methods.
- xrpl::telemetry::AppMetricGauges (xrpld) owns the 19 observable gauges
  and their callbacks, holding a reference to the core and to the
  ServiceRegistry.

MetricMacros.h and ValidationTracker move with the core. The macros need
only recording() and meter(), both core members; the core holds a tracker
by value, and a libxrpl header cannot include one from src/.

ApplicationImp owns both objects and sequences them. The core is built in
the member-init list, so every synchronous instrument exists before any
subsystem can record one. The gauges are armed once overlay_ exists, the
last service their callbacks read. Shutdown detaches the gauge callbacks
before the core drops the provider, and each shutdown step is isolated so
a failure in one cannot skip the others.

That detach call is new. detachCallbacks() had no callers, and the flag it
sets is read by the gauge callbacks but can no longer be written by the
core, so the caller now has to make the ordering explicit.

The telemetry module links xrpl.libxrpl.core and xrpl.libxrpl.protocol
PUBLIC: ValidationTracker.h takes a LedgerIndex and MetricMacros.h takes a
ServiceRegistry, both in interfaces a consumer compiles against.

Adds a MetricsRegistry gtest that drives an enabled core with telemetry on
and pins the recording() gate, stop() leaving the registry inert, and
stop() being idempotent. The libxrpl test tree no longer depends on
xrpld.telemetry at all, and the two CMake workarounds that compiled xrpld
sources into xrpl_tests are gone.

Documentation and dashboard source links follow the code to their new
paths, split between the two classes by which one now defines each metric.
2026-09-16 13:45:52 +01:00
Pratik Mankawde
8efc8e90b5 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-15 14:27:05 +01:00
Pratik Mankawde
866ab77ece docs(telemetry): describe rotation measurements without naming the host
The runbook provenance paragraph named the internal AWS dev box and a
build hash and dates. State what was measured (one mainnet node, same
host and binary, differing only in store state) without the deployment
detail, which belongs in an internal runbook, not the public repo.
2026-09-15 14:26:17 +01:00
Pratik Mankawde
a75d277a22 Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation 2026-09-09 19:22:49 +01:00
Pratik Mankawde
2b6a5733e7 merge: bring the component renames forward from phase8-log-correlation
Four doc conflicts, all where this branch had rewritten a passage that upstream
had only renamed. This branch's text is kept in seven of the eight hunks and
the spanmetrics -> span_metrics and otlp/tempo -> otlp_grpc/tempo spellings
carried into it, so the rewrite is not lost and the names stay current.

The exception is the TESTING.md span-call-count comment, where the incoming
side is the fuller text: it explains that the span_ prefix comes from the
connector's namespace setting. That side is taken.

Metric names are untouched — span_calls_total and traces_span_metrics_* are
produced by the connector's namespace, not by its component name.
2026-09-09 19:22:16 +01:00
Pratik Mankawde
6f28d46682 merge: bring the component renames forward from phase7-native-metrics
Two conflicts, both where this branch's log-pipeline additions sat next to the
upstream spanmetrics -> span_metrics rename: the config header comment, which
this branch extended with a logs line, and the integration test, where the
log-correlation step precedes the span-metrics step. This branch's content is
kept in both and the rename carried into it.
2026-09-09 19:20:45 +01:00
Pratik Mankawde
366bcaa328 merge: bring the component renames forward from phase6-statsd
Four conflicts, all where this branch's replacement of the StatsD path with
native OTLP met the upstream spanmetrics -> span_metrics rename. This branch's
design wins in every case; the rename is carried into its text rather than
reverting it, so the connector, its pipeline references, the header comment,
the TESTING.md summary and the runbook all use span_metrics while keeping the
native-OTLP wording.

One addition beyond a straight take-a-side: publish the collector's health
check port. This branch restored the health_check extension and its own
TESTING.md polls http://localhost:13133/ to decide the collector is ready, but
the port was never published on this side of docker-compose.yml, so that check
could not pass from the host. Verified the merged config loads with no
deprecation warnings and that 13133 is published exactly once.

No metric name changed: traces_span_metrics_* already read that way before the
rename, which only ever touched component names and prose.
2026-09-09 19:19:22 +01:00
Pratik Mankawde
2ee24d4ab8 merge: bring the lock-free ValidationTracker forward from phase9-metric-gap-fill
Only the phase-10 task list conflicted, in its checklist section; the tracker,
config and test files merged clean.
2026-09-09 16:10:01 +01:00
Pratik Mankawde
d141405ff3 merge: bring the lock-free ValidationTracker forward from phase8-log-correlation
The three tracker files conflicted because both sides had rewritten them. Took
the incoming lock-free class, then put this branch's two monotonic accessors
back on top of it: totalAgreementsEver() and totalMissedEver(), backed by a
gross pair incremented at first classification and left alone by the repair
branch. MetricsRegistry reads both, so dropping them would not compile.

The test file kept the incoming suite, which renames every case, and gained
this branch's two gross-counter cases adapted to the injected clock.
2026-09-09 15:59:55 +01:00
Pratik Mankawde
c622da5a76 refactor(telemetry): use the current name for the span metrics connector
The pinned collector warns on every start that "spanmetrics" is a deprecated
alias for "span_metrics". Rename the connector, its pipeline references and
the prose that names it.

The derived metric names are untouched. They come from the connector's
`namespace` setting rather than its component name, so occurrences inside a
metric name such as traces_spanmetrics_calls_total are deliberately left as
they are; renaming those would break every span panel. The rename is applied
only to the bare word, never where it is joined to a metric name by
underscores.

This branch introduces the connector, so the change belongs here.
2026-09-09 15:40:11 +01:00
Pratik Mankawde
ac07e1345f fix(telemetry): name the harness log directories after their instance ids
The collector reads the per-node directory off the log file path and stamps it
as the Loki label service_instance_id, so the directory name has to equal the
node's own [telemetry] service_instance_id or log lines carry a node name that
no trace or metric shares and nothing joins.

Both harness scripts disagreed with themselves: run-full-validation.sh wrote to
node$i while setting validator-${i}, and benchmark.sh wrote to node$i while
setting bench-node-${i}. Rename the directories to match the ids rather than
the reverse, so no existing trace or metric label value moves and no harness
expectation has to be re-checked. Only path references are renamed; the
human-readable "node$i" in log and error messages is left as prose.

The config template is not rendered by any script, so its DATA_DIR
documentation gains a note about the same constraint instead.

Also rename the deprecated otlphttp/filelog collector component names in the
harness scripts and docs.
2026-09-09 15:12:36 +01:00
Pratik Mankawde
7f8f5b4be3 feat(telemetry): ship logs through Alloy, alongside traces and metrics
Alloy carried no log pipeline at all: no loki.source, loki.write or
loki.process anywhere in the config, against a working metrics and OTLP path.
Any deployment fed through Alloy rather than the reference collector therefore
sent traces and metrics but no logs, so log-to-trace correlation was
unavailable there even though both ends of the link were configured.

Logs now leave through the same otlphttp exporter as the other two signals, so
all three carry one resource identity. Alloy's own filelog receiver would have
been the closest match to the reference collector, but it is still
public-preview and refuses to load unless the service is started with
--stability.level=public-preview, which would mean editing the unit on a box
reachable only by RunCommand. The Loki source components are generally
available, so they are used and bridged into OTLP by otelcol.receiver.loki;
the service needs no extra flag.

That bridge hands over an empty resource and puts everything on the log
record, so the transform sets the resource attributes in log context.
service.instance.id is concatenated in from XRPLD_HOST_LABEL because OTTL has
no env() converter, and it is a resource attribute rather than a record one
because only resource attributes are promoted to indexed Loki labels. It must
equal the node's own service_instance_id or the logs join nothing. devnet
writes one flat file rather than a per-node directory, so identity cannot be
read off the path the way the docker collector does it; XRPLD_LOG_GLOB
overrides the path for other layouts.

The line is parsed for its own timestamp, severity and trace context, and
trace_id/span_id are set on the first-class OTLP record fields so Grafana
links a log to its trace without re-parsing the body. Lines emitted outside a
sampled span keep an empty trace id rather than an invalid one.

Also carry the node-identity operators into the Grafana Cloud collector
variant, align this config's log directory with its service_instance_id, and
rename the deprecated otlphttp/filelog collector component names. Alloy's
otelcol.exporter.otlphttp is that product's own name and is unchanged.
2026-09-09 15:12:18 +01:00
Pratik Mankawde
cbb8581997 fix(telemetry): make the log pipeline actually deliver, and fix its docs
Addresses the open review findings on this branch.

The log root was never delivered at all. Docker creates a missing bind-mount
source as root, Config::getDebugLogFile() only warns when it cannot create the
network subdirectory inside it, and Application carries on. The node therefore
looked healthy while writing no debug.log, and Loki stayed empty with no error
at any layer. docker/telemetry/data/logs has in fact been root-owned in a
working checkout since it was first created. A one-shot xrpld-logdir-init
service now creates the directory and hands it to XRPLD_UID/XRPLD_GID,
following the pattern the storage-init service already uses.

Ingested logs carried no node identity, so a multi-node stack collapsed into
one indistinguishable stream while every dashboard filters on
service_instance_id. The receiver now sets include_file_path and lifts the
per-node directory onto the resource attribute service.instance.id, which is
on the allow-list Loki promotes to an indexed stream label. A record attribute
would only become structured metadata and could not be used in a selector.
For that to join anything the directory name has to equal the emitter's
service_instance_id, so the node directories are renamed to match: node$i
becomes Node-$i, and the standalone config writes to logs/xrpld-standalone.

The integration test aborted before reporting. Under set -o pipefail the
grep | head -1 pipeline is killed by SIGPIPE once the log exceeds the pipe
buffer, so the run exited 141 somewhere past a few hundred matching lines and
read as a flaky test. grep -m1 stops on its own. The test also verified the
local file and Tempo but never that a line reached Loki, which is the one hop
this branch adds, so a bounded Loki assertion is added alongside a readiness
wait.

Documentation fixes: the Tempo cross-check counted .data, but Tempo returns
OTLP shape so the array is batches and one trace can span several; the Loki
step used the instant /query endpoint, which rejects a bare log selector with
HTTP 400 and a text/plain body, so jq could never parse it and the step never
printed a number even when ingestion worked. The filelog comment claimed six
fractional digits where the node always emits nine. The two flowcharts used
<br/>, carried no legend, and advertised GetSpan(), which Log.cpp deliberately
avoids in favour of reading the thread-local context directly.

Finally, rename the deprecated collector component names: the pinned
collector warns on every start that otlphttp and filelog are aliases for
otlp_http and file_log. Alloy's otelcol.exporter.otlphttp and
otelcol.receiver.filelog are that product's own component names and are not
deprecated, so they are left alone.
2026-09-09 15:11:49 +01:00
Pratik Mankawde
478b3e4b07 docs(telemetry): correct stale claims and citations in the harness docs
The workload README contradicted itself on --skip-loki: one bullet said CI always
passes it and so the two log-correlation checks are never exercised, another said
the workflow no longer passes it. The workflow mentions the flag nowhere, so the
first was the stale half.

Other claims checked against the tree and corrected:

- both the README and the plan doc described the push trigger as filtered on
  branch names. The workflow has no branches filter, deliberately, because
  GitHub ANDs branches with paths
- the plan doc printed 6 of the workflow's 12 paths globs, and claimed the
  workflow was 367 lines against an actual 451. The glob block is now generated
  from the workflow, and the line count dropped rather than restated
- rpcNOT_SUPPORTED does not exist anywhere in the tree. The symbol is
  RpcNotSupported, and the refusal sites are RipplePathFind.cpp:59-60 and
  PathFind.cpp:50-51, not :48-49 and :39
- RCLConsensus.cpp:666 and :663 are not log or event lines; the tx.included event
  is at :720 and the per-transaction debug log at :715
- LedgerMaster.cpp:463 is fixIndex, not the ledger.store span, which is at :470
- ServerHandler.cpp:705 is inside makeJsonError; processRequest is at :718
- file counts: docker/telemetry/workload/ is 25 files, include/xrpl/telemetry/ 13
- the optional-span bullet named five causes covering 10 of 16 entries, omitting
  the txq.* family and the WebSocket handshake
- the /api/v1/series choice was attributed to stale StatsD gauges; this harness
  runs no StatsD

A line number in run-full-validation.sh was cited in five places and drifts on
every edit to that file, so those now name the file only. The keygen helper's
header records what production does instead -- validator-keys-tool create_keys
then create_token, keeping the master key off the node -- and why a disposable
cluster does not.
2026-09-09 13:16:13 +01:00
Pratik Mankawde
8d2e2d15af docs(telemetry): correct stale code citations and the log-correlation claim
Every citation below was checked against the file it names:

- LedgerMaster.cpp:463 is fixIndex, not the ledger.store span; that guard is at
  :470 and the insert it wraps at :476
- LedgerMaster.cpp:987 is the tvc assignment, which sits BEFORE the tvc < minVal
  return at :988; the ledger.validate span opens at :1003
- ServerHandler.cpp:705 is inside makeJsonError; processRequest is at :718
- docker-compose.yml:71 and :75 are comments in the collector's volume block;
  the loki service is at :112 and its config command at :116

Two claims were also wrong rather than merely stale. Log-trace correlation is
gated in CI, because the workflow passes no --skip-loki, and the separate check
in integration-test.sh is run by no workflow at all. The Loki label note
described the Grafana Cloud collector config rather than the local one: only the
cloud variant sets job=xrpld, and the local config's own comment says to select
on service_name. The dashboards carry 35 Loki queries, not 38.
2026-09-09 13:14:21 +01:00
Pratik Mankawde
738b5905fd merge: bring the CI fixes forward from phase9-metric-gap-fill 2026-09-08 17:22:19 +01:00
Pratik Mankawde
bae31955db merge: bring the CI fixes forward from phase8-log-correlation
One conflicted file, docs/telemetry-runbook.md, with three spots:

- Build section: both sides added different text at one point. Kept both,
  incoming sentence first, then this branch's "Run against a live network".
- Disabling section, first spot: this branch's wording names the config
  section and says no rebuild is needed, so it already covers the incoming
  sentence.
- Disabling section, second spot: kept this branch's paragraph and folded in
  the one point it lacked, that both flags have to be passed.
2026-09-08 17:22:04 +01:00
Pratik Mankawde
75f2d042f4 merge: bring the CI fixes forward from phase7-native-metrics 2026-09-08 17:19:40 +01:00
Pratik Mankawde
ff1a905ede merge: bring the CI fixes forward from phase6-statsd
Three conflicts, all resolved by keeping this branch's rewrite and
re-applying the incoming change onto it:

- 09-data-collection-reference.md: phase-7 rewrote both attribute tables,
  so the incoming table would have reverted them. Kept phase-7's and
  re-applied the two "XRPL epoch" spellings.
- integration-test.sh: phase-7 moved these checks from StatsD to OTel and
  no longer defines check_statsd_metric, so only this side compiles.
- TelemetryConfig.cpp: the incoming side carried networkTypeFromId(), which
  this branch already has. Kept one definition and took the incoming
  doc wording, which the auto-merged body below it already matches.
2026-09-08 17:17:50 +01:00
Pratik Mankawde
e612e5d9fa merge: bring the CI fixes forward from phase5-docs-deployment 2026-09-08 17:14:06 +01:00
Pratik Mankawde
9c9cb9d091 fix(telemetry): check TLS paths and fix the runbook build steps
requireReadableFile proved a path readable with getFileContents, which
loads the whole file into a std::string and then drops it. One of the
three paths it checks is tls_client_key, so a private key was loaded to
answer a question that does not need its contents. It now stats the
path, rejects anything that is not a regular file, and opens it without
reading. The message shape is unchanged:
"[telemetry] <key> cannot be read: <path> - <reason>".

A path naming a directory used to escape as an ios failure from the
stream buffer, naming neither the config key nor the path. It is now
rejected as "not a regular file" with both named. The new test covers
that case; it fails against the old implementation and against a copy
with the file-type branch removed.

The runbook's quick start and disable sections both told the reader to
run "cmake --preset default". No presets file is tracked, and the only
preset Conan generates is conan-release, so each of those steps failed
on its first command. Replaced with the flow BUILD.md documents, and
noted that telemetry is the current default while still passing the
flags.
2026-09-08 16:54:30 +01:00
Pratik Mankawde
d73e6f4020 merge: bring the review fixes forward from otel-phase9-metric-gap-fill 2026-09-08 15:53:57 +01:00
Pratik Mankawde
5542170422 docs(telemetry): drop the stale consensus_trace_strategy validation gap
The parser now maps the value onto ConsensusTraceStrategy and rejects any
other spelling, so the runbook note and the Phase 4 task-list bullet both
claimed a gap that no longer exists.
2026-09-08 15:52:58 +01:00
Pratik Mankawde
2fdfbe1b91 merge: bring the review fixes forward from otel-phase8-log-correlation 2026-09-08 15:51:07 +01:00
Pratik Mankawde
547cc8bac5 merge: bring the review fixes forward from otel-phase7-native-metrics 2026-09-08 15:46:05 +01:00
Pratik Mankawde
7d679ce596 merge: bring the review fixes forward from otel-phase6-statsd 2026-09-08 15:45:22 +01:00
Pratik Mankawde
9977810c6d merge: bring the review fixes forward from phase5-docs-deployment
One conflict, in docs/telemetry-runbook.md: both sides had independently
corrected the same consensus_round_id example. This branch kept the pipe form,
which Tempo rejects as a parse error; upstream moved the predicate inside the
braces, which parses and returns data. Upstream's query is kept, with this
branch's note that the value is the previous ledger sequence plus one.
2026-09-08 15:33:02 +01:00
Pratik Mankawde
039c2768ba fix(telemetry): require an https endpoint when a client certificate is set
The OTLP/HTTP exporter selects TLS from the endpoint URL scheme alone
(HttpSslOptions in the pinned SDK matches "https:" exactly), so a client
certificate handed to it alongside an http:// traces_endpoint is loaded and
never presented. The parser checked the cert/key pairing, use_tls and file
readability, but never the scheme, and the default traces_endpoint is plain
HTTP. makeTelemetrySetup() now requires traces_endpoint to start with
"https://" whenever tls_client_cert is set, including when the key is left
at its default.

Nothing asserted the client options reaching the exporter, so a swapped
certificate and key would have passed every test. Move the options mapping
into makeTraceExporterOptions() and assert it at that boundary with
distinct certificate and key paths, plus a one-way-TLS control and a
use_tls=0 control. One case runs the whole path from a [telemetry] section.

Runbook and example-config fixes:

- tx.included is emitted per transaction of the agreed consensus set,
  before buildLCL() applies anything, so it is a superset of the accepted
  ledger rather than proof of inclusion.
- the dispute.resolve query used the descendant operator, but the event is
  on the consensus.update_positions span itself, so it matched nothing.
- the exhausted-retries query asked for txq_status="retried" with
  retries_remaining=0, which cannot occur: the attribute is stamped before
  the attempt and the retried branch only runs while retries are left.
  Exhaustion is txq_status="failed" with a zero count.
- consensus_round_id is an int64, so the two queries comparing it to a
  quoted string matched nothing.
- note that consensus_trace_strategy=random is experimental and not used.
- note that a trailing "| attr = value" is rejected by current Tempo;
  attribute filters belong inside the braces.
2026-09-08 14:41:39 +01:00
Pratik Mankawde
5a567841f1 merge: bring the review fixes forward from otel-phase9-metric-gap-fill 2026-09-07 15:41:03 +01:00
Pratik Mankawde
623e3d8ad3 feat(telemetry): add batch-size and discovered-path histograms
Review feedback asked for a Histogram rather than a span attribute at these two
places. Both, not either: the attribute answers how big one sampled request was,
which an aggregate cannot, and the histogram answers the distribution across all
requests, which an unsampled trace never reveals. Both attributes stay.

The metrics land here rather than with the attributes because neither
HistogramBuckets.h nor the metric macro exists on the branch that added them.

Both use kObjectCountBuckets. The argument is the floor, not the ceiling: the SDK
default edges start 0,5,10,25, so an ordinary batch of one to five falls in a
single bucket and every quantile becomes an interpolation on one edge. The object
ladder puts five edges over the mass of both distributions. Path count is bounded
at 352 by kMaxPaths times kMaxAutoSrcCur and cannot saturate. Batch size can, at
roughly 333k, but no measured traffic goes near it, so the ladder is not widened
for a range nothing occupies; the runbook records the overflow query and a test
asserts it stays readable.
2026-09-07 13:51:44 +01:00
Pratik Mankawde
8c124ab14c merge: bring the close-time attr doc fixes forward from phase9-metric-gap-fill 2026-09-04 12:43:52 +01:00
Pratik Mankawde
2b61e763f7 merge: bring the close-time attr doc fixes forward from phase8-log-correlation
The runbook span table, the phase-4 task list and the data reference all
conflicted: this branch had already expanded them with the open-phase,
avalanche and proposal-prefix attributes. Keep this branch's tables and
apply the close-time rename to their rows.

The close_time entry in ledger_history_mismatch_total{reason} is a metric
label value, not the span attribute, and is deliberately unchanged.
2026-09-04 12:43:38 +01:00