Files
rippled/src/tests/libxrpl/telemetry/TxApplySpanNames.cpp
Pratik Mankawde fb76c43307 feat(telemetry): correlate tx spans to the ledger being worked on
Add shared current_ledger_seq / current_ledger_hash span attributes so a
transaction's work can be joined to the ledger trace that produced it, and
fix discrepancy D1 (txq.enqueue was a detached trace root).

- Define current_ledger_seq / current_ledger_hash once in SpanNames.h and
  re-export via `using` from TxQ/TxApply/Tx span-name headers. These name the
  ledger being worked on (open/tentative apply or in-flight consensus build),
  distinct from ledger_seq (the built/validated ledger on ledger.build /
  consensus.round). Named after the RPC field ledger_current_index.
- txq.enqueue: set current_ledger_seq/hash from the view, and parent the span
  to the caller's tx.process span via an explicit captured SpanContext (new
  trailing TxQ::apply param) instead of a detached root. The parent is
  explicit, not ambient-inherited, and the ScopedSpanGuard scope is RAII-bound
  to the synchronous apply, so it cannot leak onto a reused worker (D1 fix).
  On the open-ledger rebuild path no tx.process context exists, so it stays a
  root and the attribute provides the correlation.
- tx.preclaim / tx.transactor: set both attributes from their ledger view.
  tx.preflight is stateless (no view) and is the documented exception.
- tx.process / tx.receive: set current_ledger_seq from the current open ledger
  index at submit/receive time (no hash: not yet applied to a ledger).
- Contract test pins the two new attribute key strings.

Neither key is a spanmetrics dimension, so there is no metric-cardinality
impact. Dashboards/collector/docs land on the later phases per the chain split.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 16:03:42 +01:00

63 lines
2.7 KiB
C++

#include <xrpl/tx/detail/TxApplySpanNames.h>
#include <gtest/gtest.h>
#include <string_view>
/**
* Contract tests for the transaction apply-pipeline span constants.
*
* The span names and attribute keys in TxApplySpanNames.h are a cross-component
* contract: the collector spanmetrics connector aggregates on these exact
* strings (dimensions tx_type, ter_result, stage) and the Grafana
* transaction-overview dashboard queries them. A silent rename here would
* break per-stage metrics with no compile error, so these tests pin the
* literal values. They need no telemetry runtime and run in every build.
*/
using namespace xrpl::telemetry;
TEST(TxApplySpanNames, span_names_are_dot_qualified)
{
// Full span names feed SpanGuard::hashSpan() in applySteps.cpp.
EXPECT_EQ(std::string_view(tx_apply_span::preflight), "tx.preflight");
EXPECT_EQ(std::string_view(tx_apply_span::preclaim), "tx.preclaim");
}
TEST(TxApplySpanNames, operation_suffixes)
{
// Suffix used with SpanGuard::span(cat, seg::tx, suffix) in Transactor.cpp.
EXPECT_EQ(std::string_view(tx_apply_span::op::preflight), "preflight");
EXPECT_EQ(std::string_view(tx_apply_span::op::preclaim), "preclaim");
EXPECT_EQ(std::string_view(tx_apply_span::op::transactor), "transactor");
}
TEST(TxApplySpanNames, attribute_keys_match_collector_dimensions)
{
// These keys MUST match docker/telemetry/otel-collector-config.yaml
// spanmetrics dimensions and TxSpanNames.h (so both span sets aggregate
// under one dimension).
EXPECT_EQ(std::string_view(tx_apply_span::attr::stage), "stage");
EXPECT_EQ(std::string_view(tx_apply_span::attr::txType), "tx_type");
EXPECT_EQ(std::string_view(tx_apply_span::attr::terResult), "ter_result");
EXPECT_EQ(std::string_view(tx_apply_span::attr::applied), "applied");
}
TEST(TxApplySpanNames, stage_values_are_the_three_pipeline_stages)
{
// The stage attribute carries exactly these three values; they become the
// spanmetrics `stage` dimension cardinality (3) and the dashboard filter.
EXPECT_EQ(std::string_view(tx_apply_span::val::preflight), "preflight");
EXPECT_EQ(std::string_view(tx_apply_span::val::preclaim), "preclaim");
EXPECT_EQ(std::string_view(tx_apply_span::val::apply), "apply");
}
TEST(TxApplySpanNames, current_ledger_keys_are_shared_constants)
{
// "ledger being worked on" keys, re-exported from the base SpanNames.h so
// every emitter (tx.*, txq.*, apply pipeline) shares one string. Set on
// preclaim/transactor (view-bearing); preflight omits them (stateless).
EXPECT_EQ(std::string_view(tx_apply_span::attr::currentLedgerSeq), "current_ledger_seq");
EXPECT_EQ(std::string_view(tx_apply_span::attr::currentLedgerHash), "current_ledger_hash");
}