Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill

This commit is contained in:
Pratik Mankawde
2026-08-24 20:45:37 +01:00
6 changed files with 158 additions and 111 deletions

View File

@@ -8,6 +8,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/consensus/ConsensusProposal.h>
#include <xrpl/consensus/ConsensusSpanLabels.h>
#include <xrpl/consensus/ConsensusSpanNames.h>
#include <xrpl/consensus/ConsensusTypes.h>
#include <xrpl/json/json_value.h>
@@ -34,9 +35,9 @@ namespace xrpl {
/**
* Determines why the current ledger should close at this time.
*
* Holds the close decision that shouldCloseLedger() reduces to a bool. Call
* this one when the deciding branch matters. Both log identically, so call
* one or the other, never both. Parameters match shouldCloseLedger().
* Holds the close decision. shouldCloseLedger() delegates here and adds only
* a comparison, so the logging happens once either way; call whichever suits.
* Parameters match shouldCloseLedger().
*
* @return The deciding branch, or KeepOpen if no close condition is met.
*/
@@ -692,6 +693,24 @@ private:
*/
std::optional<xrpl::telemetry::SpanGuard> openSpan_;
/**
* Record how the open-phase span began.
*
* @param reason Which startRoundInternal() entry path created it.
* @param prevLedger The prior ledger, read before previousLedger_ is set.
*/
void
annotateOpenStart(StartRoundReason reason, Ledger_t const& prevLedger);
/**
* Record what ended the open phase.
*
* @param closeReason The deciding whyCloseLedger() branch.
* @param proposersValidated Trusted peers already past the prior ledger.
*/
void
annotateOpenClose(LedgerCloseReason closeReason, std::size_t proposersValidated);
/**
* Create the establish-phase span if not yet active.
* Called on each phaseEstablish() invocation; no-op while span is live.
@@ -811,18 +830,7 @@ Consensus<Adaptor>::startRoundInternal(
openSpan_.emplace(
telemetry::SpanGuard::childSpan(
telemetry::consensus::span::phaseOpen, adaptor_.roundSpanContext()));
if (*openSpan_)
{
namespace cs = telemetry::consensus::span;
// A recovery emplaces a SECOND phase.open span under the same round,
// so this is what tells the two apart.
openSpan_->setAttribute(
cs::attr::startReason,
reason == StartRoundReason::Recovered ? std::string_view{cs::val::startRecovered}
: std::string_view{cs::val::startInitial});
// From the parameter: previousLedger_ is not assigned until below.
openSpan_->setAttribute(cs::attr::previousCloseAgree, prevLedger.closeAgree());
}
annotateOpenStart(reason, prevLedger);
// On the Recovered path, fire phase.open here because startRoundTracing
// (which fires it for the Initial path) is not called on re-entry. On
// the Initial path this is a no-op because the round span hasn't been
@@ -1376,16 +1384,7 @@ Consensus<Adaptor>::phaseOpen(std::unique_ptr<std::stringstream> const& clog)
clog);
if (closeReason != LedgerCloseReason::KeepOpen)
{
// Annotate before closeLedger() ends the span. Set once: the phase
// moves to Establish, so phaseOpen() is not entered again this round.
// Absent on the simulate() path, which bypasses this decision.
if (openSpan_ && *openSpan_)
{
namespace cs = telemetry::consensus::span;
openSpan_->setAttribute(cs::attr::closeReason, cs::closeReasonLabel(closeReason));
openSpan_->setAttribute(
cs::attr::proposersValidated, static_cast<int64_t>(proposersValidated));
}
annotateOpenClose(closeReason, proposersValidated);
CLOG(clog) << "closing ledger. ";
closeLedger(clog);
}
@@ -2160,6 +2159,36 @@ Consensus<Adaptor>::asCloseTime(NetClock::time_point raw) const
return roundCloseTime(raw, closeResolution_);
}
template <class Adaptor>
void
Consensus<Adaptor>::annotateOpenStart(StartRoundReason const reason, Ledger_t const& prevLedger)
{
if (!openSpan_ || !*openSpan_)
return;
namespace cs = telemetry::consensus::span;
openSpan_->setAttribute(
cs::attr::startReason,
reason == StartRoundReason::Recovered ? std::string_view{cs::val::startRecovered}
: std::string_view{cs::val::startInitial});
// From the parameter: previousLedger_ is not assigned until later.
openSpan_->setAttribute(cs::attr::previousCloseAgree, prevLedger.closeAgree());
}
template <class Adaptor>
void
Consensus<Adaptor>::annotateOpenClose(
LedgerCloseReason const closeReason,
std::size_t const proposersValidated)
{
// Called before closeLedger() ends the span, and only on the closing tick,
// so each attribute is written once per round.
if (!openSpan_ || !*openSpan_)
return;
namespace cs = telemetry::consensus::span;
openSpan_->setAttribute(cs::attr::closeReason, cs::closeReasonLabel(closeReason));
openSpan_->setAttribute(cs::attr::proposersValidated, static_cast<int64_t>(proposersValidated));
}
template <class Adaptor>
void
Consensus<Adaptor>::startEstablishTracing()
@@ -2207,9 +2236,9 @@ Consensus<Adaptor>::endEstablishTracing()
// Terminal convergence regime, recorded once before the span ends.
if (establishSpan_ && *establishSpan_)
{
namespace cs = telemetry::consensus::span;
establishSpan_->setAttribute(
telemetry::consensus::span::attr::closeTimeAvalancheState,
telemetry::consensus::span::avalancheStateLabel(closeTimeAvalancheState_));
cs::attr::closeTimeAvalancheState, cs::avalancheStateLabel(closeTimeAvalancheState_));
}
establishSpan_.reset();
establishSpanContext_ = telemetry::SpanContext{};

View File

@@ -0,0 +1,85 @@
#pragma once
/**
* Enum-to-label mappings for consensus span attribute values.
*
* Split from ConsensusSpanNames.h so that header stays dependency-free like
* its siblings: the span-name and attribute-key constants are included by
* overlay and app translation units that have no use for the consensus
* enums, while these mappings are needed only by Consensus.h.
*
* ConsensusSpanNames.h (constants only, no domain deps)
* ^
* | includes
* ConsensusSpanLabels.h --includes--> ConsensusParms.h, ConsensusTypes.h
* ^
* | includes
* Consensus.h
*/
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/consensus/ConsensusSpanNames.h>
#include <xrpl/consensus/ConsensusTypes.h>
#include <string_view>
namespace xrpl::telemetry::consensus::span {
/**
* Map a close-time avalanche state to its `avalanche_state` label.
*
* The regime escalates Init -> Mid -> Late -> Stuck, raising the close-time
* agreement threshold at each step.
*
* @param state The state held by Consensus::closeTimeAvalancheState_.
* @return The wire label; one of val::avalanche*.
*
* @note No default arm, so a new enumerator is a -Wswitch warning; the
* fall-through returns "unknown" rather than a plausible-looking regime.
*/
[[nodiscard]] constexpr std::string_view
avalancheStateLabel(ConsensusParms::AvalancheState const state)
{
switch (state)
{
case ConsensusParms::AvalancheState::Init:
return val::avalancheInit;
case ConsensusParms::AvalancheState::Mid:
return val::avalancheMid;
case ConsensusParms::AvalancheState::Late:
return val::avalancheLate;
case ConsensusParms::AvalancheState::Stuck:
return val::avalancheStuck;
}
return val::unknown;
}
/**
* Map a ledger-close decision to its `close_reason` label.
*
* @param reason The value returned by whyCloseLedger().
* @return The wire label; one of val::close*.
*
* @note No default arm, so a new enumerator is a -Wswitch warning; the
* fall-through returns "unknown". `keep_open` is mapped but never emitted.
*/
[[nodiscard]] constexpr std::string_view
closeReasonLabel(LedgerCloseReason const reason)
{
switch (reason)
{
case LedgerCloseReason::KeepOpen:
return val::closeKeepOpen;
case LedgerCloseReason::Anomaly:
return val::closeAnomaly;
case LedgerCloseReason::OthersClosed:
return val::closeOthersClosed;
case LedgerCloseReason::Idle:
return val::closeIdle;
case LedgerCloseReason::Normal:
return val::closeNormal;
}
return val::unknown;
}
} // namespace xrpl::telemetry::consensus::span

View File

@@ -86,8 +86,6 @@
* +~~~ follows-from link (separate sub-tree, causal link)
*/
#include <xrpl/consensus/ConsensusParms.h>
#include <xrpl/consensus/ConsensusTypes.h>
#include <xrpl/telemetry/SpanNames.h>
#include <string_view>
@@ -194,11 +192,8 @@ inline constexpr auto earlyCloseTriggered = makeStr("early_close_triggered");
/**
* Open-phase end metadata (set on consensus.phase.open before reset).
*
* A low `tx_sets_acquired` next to a high peer_positions_at_close suggests
* tx-set fetches did not land; the reverse skew is also possible, because
* handleWrongLedger clears currPeerPositions_ but not acquired_.
* `close_reason` plus `proposers_validated` separate "the network moved on
* without us" from "the network was quiet".
* `proposers_validated` counts validators of the previous ledger, unlike
* `proposers_finished` below, which counts those already past it.
*/
inline constexpr auto openDurationMs = makeStr("open_duration_ms");
inline constexpr auto peerPositionsAtClose = makeStr("peer_positions_at_close");
@@ -349,61 +344,4 @@ inline constexpr auto closeIdle = makeStr("idle");
inline constexpr auto closeNormal = makeStr("normal");
} // namespace val
/**
* Map a close-time avalanche state to its `avalanche_state` label.
*
* The regime escalates Init -> Mid -> Late -> Stuck, raising the close-time
* agreement threshold at each step.
*
* @param state The state held by Consensus::closeTimeAvalancheState_.
* @return The wire label; one of val::avalanche*.
*
* @note No default arm, so a new enumerator is a -Wswitch warning; the
* fall-through returns "unknown" rather than a plausible-looking regime.
*/
[[nodiscard]] constexpr std::string_view
avalancheStateLabel(ConsensusParms::AvalancheState const state)
{
switch (state)
{
case ConsensusParms::AvalancheState::Init:
return val::avalancheInit;
case ConsensusParms::AvalancheState::Mid:
return val::avalancheMid;
case ConsensusParms::AvalancheState::Late:
return val::avalancheLate;
case ConsensusParms::AvalancheState::Stuck:
return val::avalancheStuck;
}
return val::unknown;
}
/**
* Map a ledger-close decision to its `close_reason` label.
*
* @param reason The value returned by whyCloseLedger().
* @return The wire label; one of val::close*.
*
* @note No default arm, so a new enumerator is a -Wswitch warning; the
* fall-through returns "unknown". `keep_open` is mapped but never emitted.
*/
[[nodiscard]] constexpr std::string_view
closeReasonLabel(LedgerCloseReason const reason)
{
switch (reason)
{
case LedgerCloseReason::KeepOpen:
return val::closeKeepOpen;
case LedgerCloseReason::Anomaly:
return val::closeAnomaly;
case LedgerCloseReason::OthersClosed:
return val::closeOthersClosed;
case LedgerCloseReason::Idle:
return val::closeIdle;
case LedgerCloseReason::Normal:
return val::closeNormal;
}
return val::unknown;
}
} // namespace xrpl::telemetry::consensus::span