Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation

This commit is contained in:
Pratik Mankawde
2026-07-20 17:45:25 +01:00
31 changed files with 1188 additions and 750 deletions

View File

@@ -1,6 +1,3 @@
Loop: xrpl.telemetry xrpld.rpc
xrpld.rpc > xrpl.telemetry
Loop: xrpld.app xrpld.overlay
xrpld.app > xrpld.overlay

View File

@@ -323,6 +323,7 @@ xrpld.rpc > xrpl.rdb
xrpld.rpc > xrpl.resource
xrpld.rpc > xrpl.server
xrpld.rpc > xrpl.shamap
xrpld.rpc > xrpl.telemetry
xrpld.rpc > xrpl.tx
xrpld.shamap > xrpl.basics
xrpld.shamap > xrpld.core

View File

@@ -1,56 +1,58 @@
#pragma once
/** Thread-local discard signaling between SpanGuard and the span processor.
SpanGuard::discard() wants to drop a span without sending it to the
exporter. The OTel SDK calls SpanProcessor::OnEnd() synchronously on the
same thread that calls Span::End(), so a thread-local flag set just before
End() and read inside OnEnd() lets FilteringSpanProcessor drop the span
before it enters the batch export queue.
This side-channel avoids inspecting the Recordable's internals (which vary
by exporter type — SpanData vs OtlpRecordable).
The flag is a *private* thread-local member of DiscardScope, mutated only by
its constructor and destructor. This gives real access control rather than a
naming convention: no code that includes this header can flip the flag
directly — it can only enter a DiscardScope (which sets and clears the flag
over its own lifetime) and observe the state via DiscardScope::isActive().
Binding set/clear to a scope also means the flag cannot leak onto the next
span even if End() were to throw.
Kept in a separate header to avoid transitive include bloat: SpanGuard.h
only needs this signaling, not the full Telemetry.h with BasicConfig/Journal.
Usage:
@code
// In SpanGuard::discard():
{
DiscardScope discardScope; // flag set for this scope only
span->End(); // OnEnd() runs synchronously, sees flag
} // flag cleared here, unconditionally
// In FilteringSpanProcessor::OnEnd():
if (DiscardScope::isActive())
return; // drop the span
@endcode
@note Thread safety: the flag is thread-local, so each thread observes only
its own discard signal — no synchronization is required.
@see SpanGuard::discard(), FilteringSpanProcessor (Telemetry.cpp)
*/
/**
* Thread-local discard signaling between SpanGuard and the span processor.
*
* SpanGuard::discard() wants to drop a span without sending it to the
* exporter. The OTel SDK calls SpanProcessor::OnEnd() synchronously on the
* same thread that calls Span::End(), so a thread-local flag set just before
* End() and read inside OnEnd() lets FilteringSpanProcessor drop the span
* before it enters the batch export queue.
*
* This side-channel avoids inspecting the Recordable's internals (which vary
* by exporter type — SpanData vs OtlpRecordable).
*
* The flag is a *private* thread-local member of DiscardScope, mutated only by
* its constructor and destructor. This gives real access control rather than a
* naming convention: no code that includes this header can flip the flag
* directly — it can only enter a DiscardScope (which sets and clears the flag
* over its own lifetime) and observe the state via DiscardScope::isActive().
* Binding set/clear to a scope also means the flag cannot leak onto the next
* span even if End() were to throw.
*
* Kept in a separate header to avoid transitive include bloat: SpanGuard.h
* only needs this signaling, not the full Telemetry.h with BasicConfig/Journal.
*
* Usage:
* @code
* // In SpanGuard::discard():
* {
* DiscardScope discardScope; // flag set for this scope only
* span->End(); // OnEnd() runs synchronously, sees flag
* } // flag cleared here, unconditionally
*
* // In FilteringSpanProcessor::OnEnd():
* if (DiscardScope::isActive())
* return; // drop the span
* @endcode
*
* @note Thread safety: the flag is thread-local, so each thread observes only
* its own discard signal — no synchronization is required.
*
* @see SpanGuard::discard(), FilteringSpanProcessor (Telemetry.cpp)
*/
namespace xrpl::telemetry {
/** RAII guard that marks the current thread's span for discard.
Sets the thread-local discard flag on construction and clears it on
destruction, so a span ended within the guard's scope is dropped by
FilteringSpanProcessor::OnEnd() while the flag stays confined to that scope.
The flag is private and mutated only here, so no other code can set it.
Non-copyable and non-movable — its sole purpose is the scoped flag lifetime.
*/
/**
* RAII guard that marks the current thread's span for discard.
*
* Sets the thread-local discard flag on construction and clears it on
* destruction, so a span ended within the guard's scope is dropped by
* FilteringSpanProcessor::OnEnd() while the flag stays confined to that scope.
* The flag is private and mutated only here, so no other code can set it.
* Non-copyable and non-movable — its sole purpose is the scoped flag lifetime.
*/
class DiscardScope
{
public:
@@ -71,9 +73,11 @@ public:
DiscardScope&
operator=(DiscardScope&&) = delete;
/** @return true if the current thread is inside a DiscardScope, i.e. the
span ending now should be dropped rather than exported. Read by
FilteringSpanProcessor::OnEnd(). */
/**
* @return true if the current thread is inside a DiscardScope, i.e. the
* span ending now should be dropped rather than exported. Read by
* FilteringSpanProcessor::OnEnd().
*/
[[nodiscard]] static bool
isActive() noexcept
{
@@ -81,8 +85,10 @@ public:
}
private:
/** Thread-local discard flag. Private, so only this class's ctor/dtor can
mutate it; observers use isActive(). One instance per thread. */
/**
* Thread-local discard flag. Private, so only this class's ctor/dtor can
* mutate it; observers use isActive(). One instance per thread.
*/
inline static thread_local bool discarding = false;
};

View File

@@ -1,63 +1,65 @@
#pragma once
/** Account-address redaction for telemetry span attributes.
Path-finding RPC handlers would otherwise emit the caller's raw
account addresses as span attributes. To keep plaintext addresses out
of the telemetry backend, they are hashed at the point of emission.
This header exposes a single pure helper that turns an address into a
short, stable, obfuscated token.
Data flow:
handler -> redactAccount(addr) -> span attribute -> OTLP export
The returned token is the first 16 hex characters (lowercase) of the
SHA-512Half digest of the address. It is deterministic (same address
always maps to the same token) so operators can still correlate spans
for a given account across nodes and restarts.
The hash is unsalted, so it is obfuscation, not a secrecy guarantee:
XRP account addresses are a public, enumerable set, so a determined
observer with the telemetry stream could rebuild the address->token
mapping. The goal here is to keep plaintext addresses out of traces
and dashboards, not to defend against a precomputation attack. A salt
is intentionally omitted because it would break cross-node/restart
correlation, which is the reason for hashing rather than dropping.
A second, independent hashing layer runs in the OpenTelemetry
Collector (an `attributes/hash` processor) as defense-in-depth for
any node that emits a raw value.
@note This function is pure and reentrant: it holds no global state,
performs no I/O, and is safe to call concurrently from any thread.
Usage example:
@code
#include <xrpl/telemetry/Redaction.h>
using namespace xrpl::telemetry;
span.setAttribute(
pathfind_span::attr::sourceAccount, redactAccount(src.asString()));
@endcode
Edge case (empty input yields empty output):
@code
assert(redactAccount("") == "");
@endcode
*/
/**
* Account-address redaction for telemetry span attributes.
*
* Path-finding RPC handlers would otherwise emit the caller's raw
* account addresses as span attributes. To keep plaintext addresses out
* of the telemetry backend, they are hashed at the point of emission.
* This header exposes a single pure helper that turns an address into a
* short, stable, obfuscated token.
*
* Data flow:
*
* handler -> redactAccount(addr) -> span attribute -> OTLP export
*
* The returned token is the first 16 hex characters (lowercase) of the
* SHA-512Half digest of the address. It is deterministic (same address
* always maps to the same token) so operators can still correlate spans
* for a given account across nodes and restarts.
*
* The hash is unsalted, so it is obfuscation, not a secrecy guarantee:
* XRP account addresses are a public, enumerable set, so a determined
* observer with the telemetry stream could rebuild the address->token
* mapping. The goal here is to keep plaintext addresses out of traces
* and dashboards, not to defend against a precomputation attack. A salt
* is intentionally omitted because it would break cross-node/restart
* correlation, which is the reason for hashing rather than dropping.
*
* A second, independent hashing layer runs in the OpenTelemetry
* Collector (an `attributes/hash` processor) as defense-in-depth for
* any node that emits a raw value.
*
* @note This function is pure and reentrant: it holds no global state,
* performs no I/O, and is safe to call concurrently from any thread.
*
* Usage example:
* @code
* #include <xrpl/telemetry/Redaction.h>
* using namespace xrpl::telemetry;
*
* span.setAttribute(
* pathfind_span::attr::sourceAccount, redactAccount(src.asString()));
* @endcode
*
* Edge case (empty input yields empty output):
* @code
* assert(redactAccount("") == "");
* @endcode
*/
#include <string>
#include <string_view>
namespace xrpl::telemetry {
/** Hash an account address into a short, stable, obfuscated token.
@param addr The account address to redact (e.g. an r-address).
@return The first 16 lowercase hex characters of sha512Half(addr),
or an empty string when @p addr is empty.
*/
/**
* Hash an account address into a short, stable, obfuscated token.
*
* @param addr The account address to redact (e.g. an r-address).
* @return The first 16 lowercase hex characters of sha512Half(addr),
* or an empty string when @p addr is empty.
*/
[[nodiscard]] std::string
redactAccount(std::string_view addr);

View File

@@ -1,18 +1,19 @@
#pragma once
/** Compile-time string concatenation utility and shared telemetry constants.
/**
* Compile-time string concatenation utility and shared telemetry constants.
*
* Provides StaticStr<N> — a compile-time string buffer that implicitly
* converts to std::string_view — and join() for dot-separated concatenation.
* Module-specific span names (e.g. RPC, consensus) live in their respective
* modules and build upon these shared primitives.
*
* @note These constants are NOT guarded by XRPL_ENABLE_TELEMETRY because
* @note These constants are NOT guarded by XRPL_ENABLE_TELEMETRY because
* call sites reference them even when SpanGuard methods are no-ops
* (the no-op stubs still accept string_view parameters). The compiler
* elides all inline constexpr values whose only uses are in dead code.
*
* @note Json::StaticString (jss.h) is a pointer wrapper without
* @note Json::StaticString (jss.h) is a pointer wrapper without
* concatenation support. boost::static_string is not constexpr.
* StaticStr<N> exists specifically for compile-time dot-join composition.
*
@@ -37,8 +38,10 @@ namespace xrpl::telemetry {
// ===== Compile-time string utility =========================================
/// Fixed-size character buffer for compile-time string operations.
/// Implicitly converts to std::string_view at zero cost.
/**
* Fixed-size character buffer for compile-time string operations.
* Implicitly converts to std::string_view at zero cost.
*/
template <std::size_t N>
struct StaticStr
{
@@ -60,11 +63,15 @@ struct StaticStr
}
};
/// Deduction guide: StaticStr from string literal.
/**
* Deduction guide: StaticStr from string literal.
*/
template <std::size_t N>
StaticStr(char const (&)[N]) -> StaticStr<N - 1>;
/// Create a StaticStr from a string literal.
/**
* Create a StaticStr from a string literal.
*/
template <std::size_t N>
constexpr auto
makeStr(char const (&str)[N])
@@ -72,7 +79,9 @@ makeStr(char const (&str)[N])
return StaticStr<N - 1>(str);
}
/// Concatenate two StaticStr values with a dot separator.
/**
* Concatenate two StaticStr values with a dot separator.
*/
template <std::size_t A, std::size_t B>
constexpr auto
join(StaticStr<A> const& lhs, StaticStr<B> const& rhs)
@@ -108,27 +117,33 @@ namespace attr {
inline constexpr auto networkId = join(join(seg::xrpl, seg::network), makeStr("id"));
inline constexpr auto networkType = join(join(seg::xrpl, seg::network), makeStr("type"));
/// Canonical shared attrs (rule 5 — <domain>_<field> underscore form).
///
/// Per the naming convention header note: shared cross-span attribute
/// keys use the underscore form, reserving the dotted xrpl.<domain>.<field>
/// form for resource attributes set on the OTel resource at startup.
/// Defined once here, aliased by domain-specific headers. These are
/// literal underscore-joined names, not dot-joined via `join()`, since
/// `join()` always inserts `.` between its arguments.
/**
* Canonical shared attrs (rule 5 — <domain>_<field> underscore form).
*
* Per the naming convention header note: shared cross-span attribute
* keys use the underscore form, reserving the dotted xrpl.<domain>.<field>
* form for resource attributes set on the OTel resource at startup.
* Defined once here, aliased by domain-specific headers. These are
* literal underscore-joined names, not dot-joined via `join()`, since
* `join()` always inserts `.` between its arguments.
*/
inline constexpr auto txHash = makeStr("tx_hash");
inline constexpr auto peerId = makeStr("peer_id");
inline constexpr auto ledgerSeq = makeStr("ledger_seq");
/// Shared close-time attrs — bare names, reused by consensus and ledger.
/**
* Shared close-time attrs — bare names, reused by consensus and ledger.
*/
inline constexpr auto closeTime = makeStr("close_time");
inline constexpr auto closeTimeCorrect = makeStr("close_time_correct");
inline constexpr auto closeResolutionMs = makeStr("close_resolution_ms");
/// Shared validation attrs — reused by the consensus and peer validation
/// spans. Same concept, same key on every span; the span name tells them
/// apart, so neither is emitter-prefixed. `ledgerHash` is a ledger-object
/// property (bare, like ledgerSeq); `fullValidation` is the is-full-validation
/// flag. Never the dotted xrpl. form (reserved for resource attrs).
/**
* Shared validation attrs — reused by the consensus and peer validation
* spans. Same concept, same key on every span; the span name tells them
* apart, so neither is emitter-prefixed. `ledgerHash` is a ledger-object
* property (bare, like ledgerSeq); `fullValidation` is the is-full-validation
* flag. Never the dotted xrpl. form (reserved for resource attrs).
*/
inline constexpr auto ledgerHash = makeStr("ledger_hash");
inline constexpr auto fullValidation = makeStr("full_validation");
} // namespace attr

View File

@@ -1,90 +1,91 @@
#pragma once
/** Abstract interface for OpenTelemetry distributed tracing.
Provides the Telemetry base class that all components use to create trace
spans. Three concrete implementations exist, selected at construction time
by makeTelemetry():
- TelemetryImpl (Telemetry.cpp): real OTel SDK integration, compiled
only when XRPL_ENABLE_TELEMETRY is defined and enabled at runtime.
- NullTelemetry (NullTelemetry.cpp): no-op stub used when telemetry is
disabled at compile time or runtime.
- NullTelemetryOtel (Telemetry.cpp): no-op stub that still depends on
the OTel API (used during transition or for testing).
Inheritance / dependency diagram:
+--------------------+
| Telemetry | (abstract, this file)
| <<interface>> |
+---------+----------+
|
+---------+-----------+-------------------+
| | |
+---+------------+ +-----+---------+ +------+----------+
| TelemetryImpl | | NullTelemetry | | NullTelemetryOtel|
| (Telemetry.cpp)| |(NullTelemetry | | (Telemetry.cpp) |
| OTel SDK | | .cpp) | | noop w/ OTel API |
+----------------+ +---------------+ +------------------+
The Setup struct holds all configuration parsed from the [telemetry]
section of xrpld.cfg. See TelemetryConfig.cpp for the parser and
cfg/xrpld-example.cfg for the available options.
OTel SDK headers are conditionally included behind XRPL_ENABLE_TELEMETRY
so that builds without telemetry have zero dependency on opentelemetry-cpp.
Usage examples:
1. Root span at a subsystem entry point (typical usage):
@code
#include <xrpld/rpc/detail/RpcSpanNames.h>
using namespace xrpl::telemetry;
// In an RPC handler dispatch:
auto guard = SpanGuard::span(
TraceCategory::Rpc, rpc_span::prefix::command, commandName);
guard.setAttribute(rpc_span::attr::command, commandName);
// ... process request
// guard destructor automatically ends the span on scope exit
@endcode
2. Child span for a sub-operation (scoped child):
@code
auto parent = SpanGuard::span(
TraceCategory::Rpc, rpc_span::prefix::rpc, rpc_span::op::process);
{
auto child = parent.childSpan(rpc_span::op::process);
child.setAttribute(rpc_span::attr::version, apiVersion);
// child ends here
}
@endcode
3. Unrelated span (cross-scope, same thread):
@code
// gRPC and RPC handlers can be active simultaneously
auto grpcSpan = SpanGuard::span(
TraceCategory::Rpc, grpc_span::prefix::grpc, grpc_span::attr::method);
auto rpcSpan = SpanGuard::span(
TraceCategory::Rpc, rpc_span::prefix::command, commandName);
// both spans end on scope exit
@endcode
4. Cross-thread context propagation:
@code
// Thread A: capture the active context while span is in scope
auto ctx = parentGuard.captureContext();
// Thread B: create child span with explicit parent
auto child = SpanGuard::childSpan(rpc_span::op::process, ctx);
@endcode
@note Thread safety: The Telemetry interface is safe for concurrent reads
(isEnabled, shouldTrace*, getTracer, startSpan) after start() completes.
setServiceInstanceId() must be called before start() and is not thread-safe.
The OTel SDK's TracerProvider and Tracer are internally thread-safe.
*/
/**
* Abstract interface for OpenTelemetry distributed tracing.
*
* Provides the Telemetry base class that all components use to create trace
* spans. Three concrete implementations exist, selected at construction time
* by makeTelemetry():
*
* - TelemetryImpl (Telemetry.cpp): real OTel SDK integration, compiled
* only when XRPL_ENABLE_TELEMETRY is defined and enabled at runtime.
* - NullTelemetry (NullTelemetry.cpp): no-op stub used when telemetry is
* disabled at compile time or runtime.
* - NullTelemetryOtel (Telemetry.cpp): no-op stub that still depends on
* the OTel API (used during transition or for testing).
*
* Inheritance / dependency diagram:
*
* +--------------------+
* | Telemetry | (abstract, this file)
* | <<interface>> |
* +---------+----------+
* |
* +---------+-----------+-------------------+
* | | |
* +---+------------+ +-----+---------+ +------+----------+
* | TelemetryImpl | | NullTelemetry | | NullTelemetryOtel|
* | (Telemetry.cpp)| |(NullTelemetry | | (Telemetry.cpp) |
* | OTel SDK | | .cpp) | | noop w/ OTel API |
* +----------------+ +---------------+ +------------------+
*
* The Setup struct holds all configuration parsed from the [telemetry]
* section of xrpld.cfg. See TelemetryConfig.cpp for the parser and
* cfg/xrpld-example.cfg for the available options.
*
* OTel SDK headers are conditionally included behind XRPL_ENABLE_TELEMETRY
* so that builds without telemetry have zero dependency on opentelemetry-cpp.
*
* Usage examples:
*
* 1. Root span at a subsystem entry point (typical usage):
* @code
* #include <xrpld/rpc/detail/RpcSpanNames.h>
* using namespace xrpl::telemetry;
*
* // In an RPC handler dispatch:
* auto guard = SpanGuard::span(
* TraceCategory::Rpc, rpc_span::prefix::command, commandName);
* guard.setAttribute(rpc_span::attr::command, commandName);
* // ... process request
* // guard destructor automatically ends the span on scope exit
* @endcode
*
* 2. Child span for a sub-operation (scoped child):
* @code
* auto parent = SpanGuard::span(
* TraceCategory::Rpc, rpc_span::prefix::rpc, rpc_span::op::process);
* {
* auto child = parent.childSpan(rpc_span::op::process);
* child.setAttribute(rpc_span::attr::version, apiVersion);
* // child ends here
* }
* @endcode
*
* 3. Unrelated span (cross-scope, same thread):
* @code
* // gRPC and RPC handlers can be active simultaneously
* auto grpcSpan = SpanGuard::span(
* TraceCategory::Rpc, grpc_span::prefix::grpc, grpc_span::attr::method);
* auto rpcSpan = SpanGuard::span(
* TraceCategory::Rpc, rpc_span::prefix::command, commandName);
* // both spans end on scope exit
* @endcode
*
* 4. Cross-thread context propagation:
* @code
* // Thread A: capture the active context while span is in scope
* auto ctx = parentGuard.captureContext();
*
* // Thread B: create child span with explicit parent
* auto child = SpanGuard::childSpan(rpc_span::op::process, ctx);
* @endcode
*
* @note Thread safety: The Telemetry interface is safe for concurrent reads
* (isEnabled, shouldTrace*, getTracer, startSpan) after start() completes.
* setServiceInstanceId() must be called before start() and is not thread-safe.
* The OTel SDK's TracerProvider and Tracer are internally thread-safe.
*/
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/config/BasicConfig.h>
@@ -108,152 +109,203 @@
namespace xrpl::telemetry {
#ifdef XRPL_ENABLE_TELEMETRY
/** OTel instrumentation scope (tracer) name. Identifies this library as the
source of spans; distinct from the `service.name` resource attribute
(Setup::serviceName), which is config-overridable. */
/**
* OTel instrumentation scope (tracer) name. Identifies this library as the
* source of spans; distinct from the `service.name` resource attribute
* (Setup::serviceName), which is config-overridable.
*/
inline constexpr std::string_view kTracerName{"xrpld"};
/** OTel instrumentation scope (meter) name. Identifies this library as the
source of metrics; symmetric with kTracerName for the tracing side. */
/**
* OTel instrumentation scope (meter) name. Identifies this library as the
* source of metrics; symmetric with kTracerName for the tracing side.
*/
inline constexpr std::string_view kMeterName{"xrpld"};
/** OTel instrumentation scope version reported for the meter. */
/**
* OTel instrumentation scope version reported for the meter.
*/
inline constexpr std::string_view kMeterVersion{"1.0.0"};
#endif
class Telemetry
{
/** Global singleton pointer, set by start()/stop() in the active
implementation. Allows SpanGuard factory methods to access the
Telemetry instance without callers passing it explicitly.
Atomic with acquire/release ordering: start()/stop() store on
the initialization thread, factory methods load on worker threads.
@see setInstance(), getInstance()
*/
/**
* Global singleton pointer, set by start()/stop() in the active
* implementation. Allows SpanGuard factory methods to access the
* Telemetry instance without callers passing it explicitly.
*
* Atomic with acquire/release ordering: start()/stop() store on
* the initialization thread, factory methods load on worker threads.
* @see setInstance(), getInstance()
*/
inline static std::atomic<Telemetry*> instance{nullptr};
public:
/** Get the global Telemetry instance.
@return Pointer to the active instance, or nullptr if not started.
*/
/**
* Get the global Telemetry instance.
* @return Pointer to the active instance, or nullptr if not started.
*/
static Telemetry*
getInstance()
{
return instance.load(std::memory_order_acquire);
}
/** Set the global Telemetry instance.
Called by start()/stop() in concrete implementations.
Tests can call this with a mock to override the global instance.
@param t Pointer to the Telemetry instance, or nullptr to clear.
*/
/**
* Set the global Telemetry instance.
* Called by start()/stop() in concrete implementations.
* Tests can call this with a mock to override the global instance.
* @param t Pointer to the Telemetry instance, or nullptr to clear.
*/
static void
setInstance(Telemetry* t)
{
instance.store(t, std::memory_order_release);
}
/** Configuration parsed from the [telemetry] section of xrpld.cfg.
All fields have sensible defaults so the section can be minimal
or omitted entirely. See TelemetryConfig.cpp for the parser.
*/
/**
* Configuration parsed from the [telemetry] section of xrpld.cfg.
*
* All fields have sensible defaults so the section can be minimal
* or omitted entirely. See TelemetryConfig.cpp for the parser.
*/
struct Setup
{
/** Master switch: true to enable tracing at runtime. */
/**
* Master switch: true to enable tracing at runtime.
*/
bool enabled = false;
/** OTel resource attribute `service.name`. */
/**
* OTel resource attribute `service.name`.
*/
std::string serviceName = "xrpld";
/** OTel resource attribute `service.version` (set from BuildInfo). */
/**
* OTel resource attribute `service.version` (set from BuildInfo).
*/
std::string serviceVersion;
/** OTel resource attribute `service.instance.id` (defaults to node
public key). */
/**
* OTel resource attribute `service.instance.id` (defaults to node
* public key).
*/
std::string serviceInstanceId;
/** OTLP/HTTP endpoint URL where spans are sent. */
/**
* OTLP/HTTP endpoint URL where spans are sent.
*/
std::string exporterEndpoint = "http://localhost:4318/v1/traces";
/** Whether to use TLS for the exporter connection. */
/**
* Whether to use TLS for the exporter connection.
*/
bool useTls = false;
/** Path to a CA certificate bundle for TLS verification. */
/**
* Path to a CA certificate bundle for TLS verification.
*/
std::string tlsCertPath;
/** Path to this node's client certificate (PEM), presented to the
collector for mutual TLS. Empty disables client-side auth, in
which case only server (one-way) TLS is used. */
/**
* Path to this node's client certificate (PEM), presented to the
* collector for mutual TLS. Empty disables client-side auth, in
* which case only server (one-way) TLS is used.
*/
std::string tlsClientCertPath;
/** Path to the private key (PEM) for tlsClientCertPath. Required
whenever tlsClientCertPath is set. */
/**
* Path to the private key (PEM) for tlsClientCertPath. Required
* whenever tlsClientCertPath is set.
*/
std::string tlsClientKeyPath;
/** Head-based sampling ratio. Intentionally fixed at 1.0 (sample
everything) and NOT read from config. A per-node ratio would let
nodes make divergent keep/drop decisions for the same distributed
trace, producing broken/partial traces. The ratio sampler is wrapped
in a ParentBasedSampler (see Telemetry.cpp) so spans inheriting a
remote parent honor the upstream sampled flag. Volume reduction is
delegated to the collector's tail sampling; for node-local post-hoc
dropping see SpanGuard::discard().
*/
/**
* Head-based sampling ratio. Intentionally fixed at 1.0 (sample
* everything) and NOT read from config. A per-node ratio would let
* nodes make divergent keep/drop decisions for the same distributed
* trace, producing broken/partial traces. The ratio sampler is wrapped
* in a ParentBasedSampler (see Telemetry.cpp) so spans inheriting a
* remote parent honor the upstream sampled flag. Volume reduction is
* delegated to the collector's tail sampling; for node-local post-hoc
* dropping see SpanGuard::discard().
*/
static constexpr double samplingRatio = 1.0;
/** Maximum number of spans per batch export. */
/**
* Maximum number of spans per batch export.
*/
std::uint32_t batchSize = 512;
/** Delay between batch exports. */
/**
* Delay between batch exports.
*/
std::chrono::milliseconds batchDelay = std::chrono::milliseconds{5000};
/** Maximum number of spans queued before dropping. */
/**
* Maximum number of spans queued before dropping.
*/
std::uint32_t maxQueueSize = 2048;
/** Network identifier, added as an OTel resource attribute. */
/**
* Network identifier, added as an OTel resource attribute.
*/
std::uint32_t networkId = 0;
/** Network type label (e.g. "mainnet", "testnet", "devnet"). */
/**
* Network type label (e.g. "mainnet", "testnet", "devnet").
*/
std::string networkType = "mainnet";
/** Enable tracing for transaction processing. */
/**
* Enable tracing for transaction processing.
*/
bool traceTransactions = true;
/** Enable tracing for consensus rounds. */
/**
* Enable tracing for consensus rounds.
*/
bool traceConsensus = true;
/** Enable tracing for RPC request handling. */
/**
* Enable tracing for RPC request handling.
*/
bool traceRpc = true;
/** Enable tracing for peer-to-peer messages (enabled by default;
high volume). */
/**
* Enable tracing for peer-to-peer messages (enabled by default;
* high volume).
*/
bool tracePeer = true;
/** Enable tracing for ledger close/accept. */
/**
* Enable tracing for ledger close/accept.
*/
bool traceLedger = true;
/** Strategy for cross-node consensus trace correlation.
"deterministic" — derive trace_id from ledger hash so all
validators in the same round share the same trace_id.
"attribute" — random trace_id, correlate via ledger_id attribute.
*/
/**
* Strategy for cross-node consensus trace correlation.
* "deterministic" — derive trace_id from ledger hash so all
* validators in the same round share the same trace_id.
* "attribute" — random trace_id, correlate via ledger_id attribute.
*/
std::string consensusTraceStrategy = "deterministic";
};
virtual ~Telemetry() = default;
/** Update the service instance ID (OTel resource attribute
`service.instance.id`).
Must be called before start(). The node public key is not available
when Telemetry is constructed (during the ApplicationImp member
initializer list), so this setter allows Application::setup() to
inject the identity once nodeIdentity_ is known.
@param id The node's base58-encoded public key or custom identifier.
*/
/**
* Update the service instance ID (OTel resource attribute
* `service.instance.id`).
*
* Must be called before start(). The node public key is not available
* when Telemetry is constructed (during the ApplicationImp member
* initializer list), so this setter allows Application::setup() to
* inject the identity once nodeIdentity_ is known.
*
* @param id The node's base58-encoded public key or custom identifier.
*/
virtual void
setServiceInstanceId(std::string const& id)
{
@@ -261,98 +313,118 @@ public:
(void)id;
}
/** Initialize the tracing pipeline (exporter, processor, provider).
Call after construction.
*/
/**
* Initialize the tracing pipeline (exporter, processor, provider).
* Call after construction.
*/
virtual void
start() = 0;
/** Flush pending spans and shut down the tracing pipeline.
Call before destruction.
*/
/**
* Flush pending spans and shut down the tracing pipeline.
* Call before destruction.
*/
virtual void
stop() = 0;
/** @return true if this instance is actively exporting spans. */
/**
* @return true if this instance is actively exporting spans.
*/
[[nodiscard]] virtual bool
isEnabled() const = 0;
/** @return true if transaction processing should be traced. */
/**
* @return true if transaction processing should be traced.
*/
[[nodiscard]] virtual bool
shouldTraceTransactions() const = 0;
/** @return true if consensus rounds should be traced. */
/**
* @return true if consensus rounds should be traced.
*/
[[nodiscard]] virtual bool
shouldTraceConsensus() const = 0;
/** @return true if RPC request handling should be traced. */
/**
* @return true if RPC request handling should be traced.
*/
[[nodiscard]] virtual bool
shouldTraceRpc() const = 0;
/** @return true if peer-to-peer messages should be traced. */
/**
* @return true if peer-to-peer messages should be traced.
*/
[[nodiscard]] virtual bool
shouldTracePeer() const = 0;
/** @return true if ledger close/accept should be traced. */
/**
* @return true if ledger close/accept should be traced.
*/
[[nodiscard]] virtual bool
shouldTraceLedger() const = 0;
/** @return The configured consensus trace correlation strategy. */
/**
* @return The configured consensus trace correlation strategy.
*/
[[nodiscard]] virtual std::string const&
getConsensusTraceStrategy() const = 0;
#ifdef XRPL_ENABLE_TELEMETRY
/** Get or create a named tracer instance.
@param name Tracer name used to identify the instrumentation library.
@return A shared pointer to the Tracer.
*/
/**
* Get or create a named tracer instance.
*
* @param name Tracer name used to identify the instrumentation library.
* @return A shared pointer to the Tracer.
*/
virtual opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer>
getTracer(std::string_view name = kTracerName) = 0;
/** Get or create a named meter instance.
Returns the raw OTel Meter, giving developers direct access to the
full metrics API. From the returned Meter any instrument type can be
created: Counter, UpDownCounter, Gauge, and Histogram (synchronous),
plus their observable/async variants (ObservableCounter,
ObservableUpDownCounter, ObservableGauge).
@param name Meter name used to identify the instrumentation scope.
@return A shared pointer to the Meter.
*/
/**
* Get or create a named meter instance.
*
* Returns the raw OTel Meter, giving developers direct access to the
* full metrics API. From the returned Meter any instrument type can be
* created: Counter, UpDownCounter, Gauge, and Histogram (synchronous),
* plus their observable/async variants (ObservableCounter,
* ObservableUpDownCounter, ObservableGauge).
*
* @param name Meter name used to identify the instrumentation scope.
* @return A shared pointer to the Meter.
*/
virtual opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter>
getMeter(std::string_view name = kMeterName) = 0;
/** Start a new span on the current thread's context.
The span becomes a child of the current active span (if any) via
OpenTelemetry's context propagation.
@param name Span name (typically "rpc.command.<cmd>").
@param kind The span kind (defaults to kInternal). Possible values:
- kInternal: default, in-process operation
- kServer: incoming synchronous request (e.g. RPC)
- kClient: outgoing synchronous request
- kProducer: async message send (e.g. peer broadcast)
- kConsumer: async message receive
@return A shared pointer to the new Span.
*/
/**
* Start a new span on the current thread's context.
*
* The span becomes a child of the current active span (if any) via
* OpenTelemetry's context propagation.
*
* @param name Span name (typically "rpc.command.<cmd>").
* @param kind The span kind (defaults to kInternal). Possible values:
* - kInternal: default, in-process operation
* - kServer: incoming synchronous request (e.g. RPC)
* - kClient: outgoing synchronous request
* - kProducer: async message send (e.g. peer broadcast)
* - kConsumer: async message receive
* @return A shared pointer to the new Span.
*/
virtual opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>
startSpan(
std::string_view name,
opentelemetry::trace::SpanKind kind = opentelemetry::trace::SpanKind::kInternal) = 0;
/** Start a new span with an explicit parent context.
Use this overload when the parent span is not on the current
thread's context stack (e.g. cross-thread trace propagation).
@param name Span name.
@param parentContext The parent span's context.
@param kind The span kind (defaults to kInternal).
@return A shared pointer to the new Span.
*/
/**
* Start a new span with an explicit parent context.
*
* Use this overload when the parent span is not on the current
* thread's context stack (e.g. cross-thread trace propagation).
*
* @param name Span name.
* @param parentContext The parent span's context.
* @param kind The span kind (defaults to kInternal).
* @return A shared pointer to the new Span.
*/
virtual opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>
startSpan(
std::string_view name,
@@ -361,26 +433,28 @@ public:
#endif
};
/** Create a Telemetry instance.
Returns a TelemetryImpl when setup.enabled is true, or a
NullTelemetry no-op stub otherwise.
@param setup Configuration from the [telemetry] config section.
@param journal Journal for log output during initialization.
*/
/**
* Create a Telemetry instance.
*
* Returns a TelemetryImpl when setup.enabled is true, or a
* NullTelemetry no-op stub otherwise.
*
* @param setup Configuration from the [telemetry] config section.
* @param journal Journal for log output during initialization.
*/
std::unique_ptr<Telemetry>
makeTelemetry(Telemetry::Setup const& setup, beast::Journal journal);
/** Parse the [telemetry] config section into a Setup struct.
@param section The [telemetry] config section.
@param nodePublicKey Node public key, used as default instance ID.
@param version Build version string.
@param networkId Network identifier from [network_id] config
(0 = mainnet, 1 = testnet, 2 = devnet).
@return A populated Setup struct with defaults for missing values.
*/
/**
* Parse the [telemetry] config section into a Setup struct.
*
* @param section The [telemetry] config section.
* @param nodePublicKey Node public key, used as default instance ID.
* @param version Build version string.
* @param networkId Network identifier from [network_id] config
* (0 = mainnet, 1 = testnet, 2 = devnet).
* @return A populated Setup struct with defaults for missing values.
*/
Telemetry::Setup
makeTelemetrySetup(
Section const& section,
@@ -388,14 +462,15 @@ makeTelemetrySetup(
std::string const& version,
std::uint32_t networkId);
/** Derive a human-readable network type label from the numeric network ID.
Shared by the trace and metric export paths so both stamp the same
`xrpl.network.type` resource attribute value.
@param networkId The network identifier from [network_id] config.
@return "mainnet" (0), "testnet" (1), "devnet" (2), or "unknown".
*/
/**
* Derive a human-readable network type label from the numeric network ID.
*
* Shared by the trace and metric export paths so both stamp the same
* `xrpl.network.type` resource attribute value.
*
* @param networkId The network identifier from [network_id] config.
* @return "mainnet" (0), "testnet" (1), "devnet" (2), or "unknown".
*/
std::string
networkTypeFromId(std::uint32_t networkId);

View File

@@ -1,18 +1,19 @@
#pragma once
/** Utilities for trace context propagation across nodes.
Provides serialization/deserialization of OTel trace context to/from
Protocol Buffer TraceContext messages (P2P cross-node propagation).
Wired into the P2P message flow via PropagationHelpers.h for
TMTransaction, TMProposeSet, and TMValidation messages.
Only compiled when XRPL_ENABLE_TELEMETRY is defined.
@see PropagationHelpers.h (high-level inject helpers),
TxTracing.h (transaction receive-side extraction),
ConsensusReceiveTracing.h (proposal/validation receive-side).
*/
/**
* Utilities for trace context propagation across nodes.
*
* Provides serialization/deserialization of OTel trace context to/from
* Protocol Buffer TraceContext messages (P2P cross-node propagation).
* Wired into the P2P message flow via PropagationHelpers.h for
* TMTransaction, TMProposeSet, and TMValidation messages.
*
* Only compiled when XRPL_ENABLE_TELEMETRY is defined.
*
* @see PropagationHelpers.h (high-level inject helpers),
* TxTracing.h (transaction receive-side extraction),
* ConsensusReceiveTracing.h (proposal/validation receive-side).
*/
#ifdef XRPL_ENABLE_TELEMETRY
@@ -35,12 +36,13 @@
namespace xrpl::telemetry {
/** Extract OTel context from a protobuf TraceContext message.
@param proto The protobuf TraceContext received from a peer.
@return An OTel Context with the extracted parent span, or an empty
context if the protobuf fields are missing or invalid.
*/
/**
* Extract OTel context from a protobuf TraceContext message.
*
* @param proto The protobuf TraceContext received from a peer.
* @return An OTel Context with the extracted parent span, or an empty
* context if the protobuf fields are missing or invalid.
*/
inline opentelemetry::context::Context
extractFromProtobuf(protocol::TraceContext const& proto)
{
@@ -69,11 +71,12 @@ extractFromProtobuf(protocol::TraceContext const& proto)
opentelemetry::nostd::shared_ptr<trace::Span>(new trace::DefaultSpan(spanCtx)));
}
/** Inject the current span's trace context into a protobuf TraceContext.
@param ctx The OTel context containing the span to propagate.
@param proto The protobuf TraceContext to populate.
*/
/**
* Inject the current span's trace context into a protobuf TraceContext.
*
* @param ctx The OTel context containing the span to propagate.
* @param proto The protobuf TraceContext to populate.
*/
inline void
injectToProtobuf(opentelemetry::context::Context const& ctx, protocol::TraceContext& proto)
{

View File

@@ -1,6 +1,7 @@
#pragma once
/** Validation predicates for peer-supplied trace context.
/**
* Validation predicates for peer-supplied trace context.
*
* A protobuf TraceContext arrives inside untrusted peer messages
* (TMTransaction, TMProposeSet, TMValidation). Before a receiving node
@@ -28,7 +29,7 @@
* no OpenTelemetry headers, so receive sites that use SpanGuard keep
* SpanGuard's encapsulation of OTel types.
*
* @note Thread-safe: all functions are pure and operate only on their
* @note Thread-safe: all functions are pure and operate only on their
* arguments. No shared state.
*
* Usage:
@@ -50,10 +51,11 @@
namespace xrpl::telemetry {
/** True if the bytes are a valid OTel trace_id: 16 bytes, not all-zero.
/**
* True if the bytes are a valid OTel trace_id: 16 bytes, not all-zero.
*
* @param traceId The raw trace_id bytes from a protobuf TraceContext.
* @return true if usable as a trace identifier, false otherwise.
* @param traceId The raw trace_id bytes from a protobuf TraceContext.
* @return true if usable as a trace identifier, false otherwise.
*/
inline bool
isValidTraceId(std::string const& traceId)
@@ -61,10 +63,11 @@ isValidTraceId(std::string const& traceId)
return traceId.size() == 16 && std::ranges::any_of(traceId, [](char c) { return c != 0; });
}
/** True if the bytes are a valid OTel span_id: 8 bytes, not all-zero.
/**
* True if the bytes are a valid OTel span_id: 8 bytes, not all-zero.
*
* @param spanId The raw span_id bytes from a protobuf TraceContext.
* @return true if usable as a span identifier, false otherwise.
* @param spanId The raw span_id bytes from a protobuf TraceContext.
* @return true if usable as a span identifier, false otherwise.
*/
inline bool
isValidSpanId(std::string const& spanId)
@@ -72,15 +75,16 @@ isValidSpanId(std::string const& spanId)
return spanId.size() == 8 && std::ranges::any_of(spanId, [](char c) { return c != 0; });
}
/** True if the context carries a usable parent: a valid trace_id and a
/**
* True if the context carries a usable parent: a valid trace_id and a
* valid span_id together.
*
* Use this where both ids are taken from the peer (consensus receive,
* generic extraction). The transaction path derives its trace_id
* locally from the txID, so it checks isValidSpanId() alone instead.
*
* @param tc The protobuf TraceContext received from a peer.
* @return true if both ids are present and valid, false otherwise.
* @param tc The protobuf TraceContext received from a peer.
* @return true if both ids are present and valid, false otherwise.
*/
inline bool
isValidTraceContext(protocol::TraceContext const& tc)

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for the transaction apply pipeline.
/**
* Compile-time span name constants for the transaction apply pipeline.
*
* Defines the span names and attribute keys used by the three apply-pipeline
* stages — preflight, preclaim, and transactor (apply) — that run inside the
@@ -67,47 +68,73 @@ namespace xrpl::telemetry::tx_apply_span {
// ===== Span operation suffixes =============================================
namespace op {
/// "preflight" — stateless transaction checks (suffix form).
/**
* "preflight" — stateless transaction checks (suffix form).
*/
inline constexpr auto preflight = makeStr("preflight");
/// "preclaim" — ledger-aware checks before fee claim (suffix form).
/**
* "preclaim" — ledger-aware checks before fee claim (suffix form).
*/
inline constexpr auto preclaim = makeStr("preclaim");
/// "transactor" — the apply stage (suffix form, used with span()).
/**
* "transactor" — the apply stage (suffix form, used with span()).
*/
inline constexpr auto transactor = makeStr("transactor");
} // namespace op
// ===== Full span names (tx.<op>) ===========================================
/// "tx.preflight" — full name for hashSpan() at the preflight stage.
/**
* "tx.preflight" — full name for hashSpan() at the preflight stage.
*/
inline constexpr auto preflight = join(seg::tx, op::preflight);
/// "tx.preclaim" — full name for hashSpan() at the preclaim stage.
/**
* "tx.preclaim" — full name for hashSpan() at the preclaim stage.
*/
inline constexpr auto preclaim = join(seg::tx, op::preclaim);
/// "tx.transactor" — full name for hashSpan() at the apply stage. Shares the
/// txID-derived trace_id so it co-traces with tx.preflight and tx.preclaim.
/**
* "tx.transactor" — full name for hashSpan() at the apply stage. Shares the
* txID-derived trace_id so it co-traces with tx.preflight and tx.preclaim.
*/
inline constexpr auto transactor = join(seg::tx, op::transactor);
// ===== Attribute keys ======================================================
namespace attr {
/// "stage" — which apply-pipeline stage this span represents. Drives the
/// collector spanmetrics `stage` dimension for per-stage RED metrics.
/**
* "stage" — which apply-pipeline stage this span represents. Drives the
* collector spanmetrics `stage` dimension for per-stage RED metrics.
*/
inline constexpr auto stage = makeStr("stage");
/// "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
/// Matches tx_span::attr::txType so both share the spanmetrics dimension.
/**
* "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
* Matches tx_span::attr::txType so both share the spanmetrics dimension.
*/
inline constexpr auto txType = makeStr("tx_type");
/// "ter_result" — engine result code after the stage (e.g., "tesSUCCESS").
/**
* "ter_result" — engine result code after the stage (e.g., "tesSUCCESS").
*/
inline constexpr auto terResult = makeStr("ter_result");
/// "applied" — whether the transaction was applied to the ledger (apply only).
/**
* "applied" — whether the transaction was applied to the ledger (apply only).
*/
inline constexpr auto applied = makeStr("applied");
} // namespace attr
// ===== Attribute values (stage names) ======================================
namespace val {
/// "preflight" — value of the stage attribute on tx.preflight.
/**
* "preflight" — value of the stage attribute on tx.preflight.
*/
inline constexpr auto preflight = makeStr("preflight");
/// "preclaim" — value of the stage attribute on tx.preclaim.
/**
* "preclaim" — value of the stage attribute on tx.preclaim.
*/
inline constexpr auto preclaim = makeStr("preclaim");
/// "apply" — value of the stage attribute on tx.transactor.
/**
* "apply" — value of the stage attribute on tx.transactor.
*/
inline constexpr auto apply = makeStr("apply");
} // namespace val

View File

@@ -108,10 +108,14 @@ public:
callHandler();
private:
/** Owning collector. Prevents collector destruction while hook alive. */
/**
* Owning collector. Prevents collector destruction while hook alive.
*/
std::shared_ptr<OTelCollectorImp> impl_;
/** User-supplied handler called at each collection interval. */
/**
* User-supplied handler called at each collection interval.
*/
HandlerType handler_;
};
@@ -152,7 +156,9 @@ public:
increment(value_type amount) override;
private:
/** OTel synchronous counter instrument. */
/**
* OTel synchronous counter instrument.
*/
opentelemetry::nostd::unique_ptr<metrics_api::Counter<uint64_t>> counter_;
};
@@ -194,7 +200,9 @@ public:
notify(value_type const& value) override;
private:
/** OTel histogram instrument for recording durations. */
/**
* OTel histogram instrument for recording durations.
*/
opentelemetry::nostd::unique_ptr<metrics_api::Histogram<double>> histogram_;
};
@@ -260,18 +268,26 @@ public:
OTelGaugeImpl&
operator=(OTelGaugeImpl const&) = delete;
/** Static callback registered with the OTel SDK observable gauge. */
/**
* Static callback registered with the OTel SDK observable gauge.
*/
static void
gaugeCallback(opentelemetry::metrics::ObserverResult result, void* state);
private:
/** Current gauge value, updated atomically by set()/increment(). */
/**
* Current gauge value, updated atomically by set()/increment().
*/
std::atomic<int64_t> value_{0};
/** OTel observable gauge handle (prevents deregistration). */
/**
* OTel observable gauge handle (prevents deregistration).
*/
opentelemetry::nostd::shared_ptr<metrics_api::ObservableInstrument> gauge_;
/** Owning collector, used to invoke hooks before reading gauge values. */
/**
* Owning collector, used to invoke hooks before reading gauge values.
*/
std::shared_ptr<OTelCollectorImp> collector_;
};
@@ -316,7 +332,9 @@ public:
increment(value_type amount) override;
private:
/** OTel synchronous counter instrument (unsigned). */
/**
* OTel synchronous counter instrument (unsigned).
*/
opentelemetry::nostd::unique_ptr<metrics_api::Counter<uint64_t>> counter_;
};
@@ -411,7 +429,9 @@ public:
*/
~OTelCollectorImp() override;
/** @name Collector interface implementation */
/**
* @name Collector interface implementation
*/
/** @{ */
Hook
makeHook(HookImpl::HandlerType const& handler) override;
@@ -429,7 +449,9 @@ public:
makeMeter(std::string const& name) override;
/** @} */
/** @name Hook management for observable callbacks */
/**
* @name Hook management for observable callbacks
*/
/** @{ */
/**
@@ -456,7 +478,9 @@ public:
callHooks();
/** @} */
/** @name Gauge registration for observable callbacks */
/**
* @name Gauge registration for observable callbacks
*/
/** @{ */
/**
@@ -495,22 +519,34 @@ public:
formatName(std::string const& name);
private:
/** Journal for log output. */
/**
* Journal for log output.
*/
Journal journal_;
/** Prefix for all metric names (e.g., "xrpld"). */
/**
* Prefix for all metric names (e.g., "xrpld").
*/
std::string prefix_;
/** OTel Meter used to create all instruments. */
/**
* OTel Meter used to create all instruments.
*/
opentelemetry::nostd::shared_ptr<metrics_api::Meter> otelMeter_;
/** Mutex protecting hook and gauge registration lists. */
/**
* Mutex protecting hook and gauge registration lists.
*/
std::mutex mutex_;
/** Registered hooks called during observable callbacks. */
/**
* Registered hooks called during observable callbacks.
*/
std::vector<OTelHookImpl*> hooks_;
/** Registered gauges read during observable callbacks. */
/**
* Registered gauges read during observable callbacks.
*/
std::vector<OTelGaugeImpl*> gauges_;
/**

View File

@@ -1,14 +1,15 @@
/** No-op implementation of the Telemetry interface.
Always compiled (regardless of XRPL_ENABLE_TELEMETRY). Provides the
makeTelemetry() factory when telemetry is compiled out (#ifndef), which
unconditionally returns a NullTelemetry that does nothing.
When XRPL_ENABLE_TELEMETRY IS defined, the OTel virtual methods
(getTracer, startSpan) return noop tracers/spans. The makeTelemetry()
factory in this file is not used in that case -- Telemetry.cpp provides
its own factory that can return the real TelemetryImpl.
*/
/**
* No-op implementation of the Telemetry interface.
*
* Always compiled (regardless of XRPL_ENABLE_TELEMETRY). Provides the
* makeTelemetry() factory when telemetry is compiled out (#ifndef), which
* unconditionally returns a NullTelemetry that does nothing.
*
* When XRPL_ENABLE_TELEMETRY IS defined, the OTel virtual methods
* (getTracer, startSpan) return noop tracers/spans. The makeTelemetry()
* factory in this file is not used in that case -- Telemetry.cpp provides
* its own factory that can return the real TelemetryImpl.
*/
#include <xrpl/telemetry/Telemetry.h>
@@ -31,14 +32,17 @@ namespace xrpl::telemetry {
namespace {
/** No-op Telemetry that returns immediately from every method.
Used as the sole implementation when XRPL_ENABLE_TELEMETRY is not
defined, or as a fallback when it is defined but enabled=0.
*/
/**
* No-op Telemetry that returns immediately from every method.
*
* Used as the sole implementation when XRPL_ENABLE_TELEMETRY is not
* defined, or as a fallback when it is defined but enabled=0.
*/
class NullTelemetry : public Telemetry
{
/** Retained configuration (unused, kept for diagnostic access). */
/**
* Retained configuration (unused, kept for diagnostic access).
*/
Setup const setup_;
public:
@@ -130,9 +134,10 @@ public:
} // namespace
/** Factory used when XRPL_ENABLE_TELEMETRY is not defined.
Unconditionally returns a NullTelemetry instance.
*/
/**
* Factory used when XRPL_ENABLE_TELEMETRY is not defined.
* Unconditionally returns a NullTelemetry instance.
*/
#ifndef XRPL_ENABLE_TELEMETRY
std::unique_ptr<Telemetry>
makeTelemetry(Telemetry::Setup const& setup, beast::Journal)

View File

@@ -1,17 +1,18 @@
/** OpenTelemetry SDK implementation of the Telemetry interface.
Compiled only when XRPL_ENABLE_TELEMETRY is defined (via CMake
telemetry=ON). Contains:
- FilteringSpanProcessor: decorator that drops spans marked with
kDiscardedAttr before they enter the batch export queue.
- TelemetryImpl: configures the OTel SDK with an OTLP/HTTP exporter,
FilteringSpanProcessor wrapping a batch span processor,
trace-ID-ratio sampler, and resource attributes.
- NullTelemetryOtel: no-op fallback used when telemetry is compiled in
but disabled at runtime (enabled=0 in config).
- makeTelemetry(): factory that selects the appropriate implementation.
*/
/**
* OpenTelemetry SDK implementation of the Telemetry interface.
*
* Compiled only when XRPL_ENABLE_TELEMETRY is defined (via CMake
* telemetry=ON). Contains:
*
* - FilteringSpanProcessor: decorator that drops spans marked with
* kDiscardedAttr before they enter the batch export queue.
* - TelemetryImpl: configures the OTel SDK with an OTLP/HTTP exporter,
* FilteringSpanProcessor wrapping a batch span processor,
* trace-ID-ratio sampler, and resource attributes.
* - NullTelemetryOtel: no-op fallback used when telemetry is compiled in
* but disabled at runtime (enabled=0 in config).
* - makeTelemetry(): factory that selects the appropriate implementation.
*/
#ifdef XRPL_ENABLE_TELEMETRY
@@ -79,39 +80,40 @@ namespace metrics_sdk = opentelemetry::sdk::metrics;
namespace otlp_http = opentelemetry::exporter::otlp;
namespace resource = opentelemetry::sdk::resource;
/** SpanProcessor decorator that drops discarded spans.
Wraps a delegate processor (typically BatchSpanProcessor). In OnEnd(),
calls DiscardScope::isActive(). If the calling thread is inside a
DiscardScope (entered by SpanGuard::discard()), the span is silently
dropped — never entering the batch queue, never sent over the network,
never stored.
Uses a thread-local flag rather than inspecting Recordable attributes
because the Recordable type varies by exporter (SpanData for simple
exporters, OtlpRecordable for OTLP) and none expose a uniform getter.
The flag is safe because Span::End() calls OnEnd() synchronously on
the same thread.
All other methods delegate directly to the wrapped processor.
Dependency diagram:
+---------------------------+
| FilteringSpanProcessor |
+---------------------------+
| - delegate_ : unique_ptr |
| <SpanProcessor> |
+---------------------------+
| wraps
+---------+-----------+
| BatchSpanProcessor |
+---------------------+
@note Thread safety: OnEnd() may be called concurrently from multiple
threads. The discard flag behind DiscardScope is thread-local, so each
thread's discard state is independent — no synchronization needed.
*/
/**
* SpanProcessor decorator that drops discarded spans.
*
* Wraps a delegate processor (typically BatchSpanProcessor). In OnEnd(),
* calls DiscardScope::isActive(). If the calling thread is inside a
* DiscardScope (entered by SpanGuard::discard()), the span is silently
* dropped — never entering the batch queue, never sent over the network,
* never stored.
*
* Uses a thread-local flag rather than inspecting Recordable attributes
* because the Recordable type varies by exporter (SpanData for simple
* exporters, OtlpRecordable for OTLP) and none expose a uniform getter.
* The flag is safe because Span::End() calls OnEnd() synchronously on
* the same thread.
*
* All other methods delegate directly to the wrapped processor.
*
* Dependency diagram:
*
* +---------------------------+
* | FilteringSpanProcessor |
* +---------------------------+
* | - delegate_ : unique_ptr |
* | <SpanProcessor> |
* +---------------------------+
* | wraps
* +---------+-----------+
* | BatchSpanProcessor |
* +---------------------+
*
* @note Thread safety: OnEnd() may be called concurrently from multiple
* threads. The discard flag behind DiscardScope is thread-local, so each
* thread's discard state is independent — no synchronization needed.
*/
class FilteringSpanProcessor : public trace_sdk::SpanProcessor
{
std::unique_ptr<trace_sdk::SpanProcessor> delegate_;
@@ -163,15 +165,18 @@ public:
}
};
/** No-op implementation used when XRPL_ENABLE_TELEMETRY is defined but
setup.enabled is false at runtime.
Lives in the anonymous namespace so there is no ODR conflict with the
NullTelemetry in NullTelemetry.cpp.
*/
/**
* No-op implementation used when XRPL_ENABLE_TELEMETRY is defined but
* setup.enabled is false at runtime.
*
* Lives in the anonymous namespace so there is no ODR conflict with the
* NullTelemetry in NullTelemetry.cpp.
*/
class NullTelemetryOtel : public Telemetry
{
/** Retained configuration (unused, kept for diagnostic access). */
/**
* Retained configuration (unused, kept for diagnostic access).
*/
Setup const setup_;
public:
@@ -265,35 +270,41 @@ public:
}
};
/** Full OTel SDK implementation that exports trace spans via OTLP/HTTP.
Configures an OTLP/HTTP exporter, batch span processor,
TraceIdRatioBasedSampler, and resource attributes on start().
*/
/**
* Full OTel SDK implementation that exports trace spans via OTLP/HTTP.
*
* Configures an OTLP/HTTP exporter, batch span processor,
* TraceIdRatioBasedSampler, and resource attributes on start().
*/
class TelemetryImpl : public Telemetry
{
/** Configuration from the [telemetry] config section.
Non-const so setServiceInstanceId() can update the instance ID
before start() creates the OTel resource.
*/
/**
* Configuration from the [telemetry] config section.
* Non-const so setServiceInstanceId() can update the instance ID
* before start() creates the OTel resource.
*/
Setup setup_;
/** Journal used for log output during start/stop. */
/**
* Journal used for log output during start/stop.
*/
beast::Journal const journal_;
/** The SDK TracerProvider that owns the export pipeline.
Held as std::shared_ptr so we can call ForceFlush() on shutdown.
Wrapped in a nostd::shared_ptr when registered as the global provider.
*/
/**
* The SDK TracerProvider that owns the export pipeline.
*
* Held as std::shared_ptr so we can call ForceFlush() on shutdown.
* Wrapped in a nostd::shared_ptr when registered as the global provider.
*/
std::shared_ptr<trace_sdk::TracerProvider> sdkProvider_;
/** The SDK MeterProvider that owns the metric export pipeline.
Symmetric with sdkProvider_ on the tracing side. Held as
std::shared_ptr so we can ForceFlush() on shutdown; wrapped in a
nostd::shared_ptr when registered as the global meter provider.
*/
/**
* The SDK MeterProvider that owns the metric export pipeline.
*
* Symmetric with sdkProvider_ on the tracing side. Held as
* std::shared_ptr so we can ForceFlush() on shutdown; wrapped in a
* nostd::shared_ptr when registered as the global meter provider.
*/
std::shared_ptr<metrics_sdk::MeterProvider> meterProvider_;
public:

View File

@@ -1,11 +1,12 @@
/** Parser for the [telemetry] section of xrpld.cfg.
Reads configuration values from the config file and populates a
Telemetry::Setup struct. All options have sensible defaults so the
section can be minimal or omitted entirely.
See cfg/xrpld-example.cfg for the full list of available options.
*/
/**
* Parser for the [telemetry] section of xrpld.cfg.
*
* Reads configuration values from the config file and populates a
* Telemetry::Setup struct. All options have sensible defaults so the
* section can be minimal or omitted entirely.
*
* See cfg/xrpld-example.cfg for the full list of available options.
*/
#include <xrpl/basics/contract.h>
#include <xrpl/config/BasicConfig.h>
@@ -20,13 +21,14 @@ namespace xrpl::telemetry {
namespace {
/** Config key names for the [telemetry] section.
Each must match the corresponding option documented in
cfg/xrpld-example.cfg verbatim. Defined as `char const*` so they
pass to Section::valueOr() (which takes `std::string const&`)
without an explicit conversion, exactly as a literal would.
*/
/**
* Config key names for the [telemetry] section.
*
* Each must match the corresponding option documented in
* cfg/xrpld-example.cfg verbatim. Defined as `char const*` so they
* pass to Section::valueOr() (which takes `std::string const&`)
* without an explicit conversion, exactly as a literal would.
*/
namespace key {
constexpr char const* enabled = "enabled";
constexpr char const* serviceName = "service_name";
@@ -46,13 +48,14 @@ constexpr char const* tracePeer = "trace_peer";
constexpr char const* traceLedger = "trace_ledger";
} // namespace key
/** Default values applied when a key is absent from the config.
@note serviceName mirrors SystemParameters' systemName() ("xrpld") but
is duplicated here as a literal: the telemetry module deliberately does
not link xrpl.libxrpl.protocol, so including SystemParameters.h would
introduce an undeclared cross-module dependency.
*/
/**
* Default values applied when a key is absent from the config.
*
* @note serviceName mirrors SystemParameters' systemName() ("xrpld") but
* is duplicated here as a literal: the telemetry module deliberately does
* not link xrpl.libxrpl.protocol, so including SystemParameters.h would
* introduce an undeclared cross-module dependency.
*/
namespace dflt {
constexpr char const* serviceName = "xrpld";
constexpr char const* endpoint = "http://localhost:4318/v1/traces";
@@ -63,8 +66,15 @@ constexpr std::uint32_t maxQueueSize = 2048u;
} // namespace
// Declared in Telemetry.h; shared by the trace and metric export paths so
// both stamp the same xrpl.network.type resource attribute value.
/**
* Derive a human-readable network type label from the numeric network ID.
*
* Declared in Telemetry.h; shared by the trace and metric export paths so
* both stamp the same xrpl.network.type resource attribute value.
*
* @param networkId The network identifier from [network_id] config.
* @return "mainnet", "testnet", "devnet", or "unknown" for other values.
*/
std::string
networkTypeFromId(std::uint32_t networkId)
{

View File

@@ -1,19 +1,20 @@
/** @file GetMeter.cpp
Unit tests for the direct OTel metrics API surface:
- xrpl::telemetry::Telemetry::getMeter() on the disabled (noop) path.
- The global MeterProvider contract that beast's OTelCollector shim
relies on (GetMeterProvider()->GetMeter(kMeterName, kMeterVersion)).
These tests deliberately exercise the global-provider level rather than a
fully started TelemetryImpl: TelemetryImpl::start() spins up an OTLP HTTP
exporter with background export threads and network connect attempts, which
is unsuitable for a hermetic unit test. The design spec permits testing the
metrics unlock at the provider level, which is the exact path the beast shim
and getMeter() delegate to.
Compiled only when XRPL_ENABLE_TELEMETRY is defined; the metrics API and SDK
headers exist only in that build.
*/
/**
* @file GetMeter.cpp
* Unit tests for the direct OTel metrics API surface:
* - xrpl::telemetry::Telemetry::getMeter() on the disabled (noop) path.
* - The global MeterProvider contract that beast's OTelCollector shim
* relies on (GetMeterProvider()->GetMeter(kMeterName, kMeterVersion)).
*
* These tests deliberately exercise the global-provider level rather than a
* fully started TelemetryImpl: TelemetryImpl::start() spins up an OTLP HTTP
* exporter with background export threads and network connect attempts, which
* is unsuitable for a hermetic unit test. The design spec permits testing the
* metrics unlock at the provider level, which is the exact path the beast shim
* and getMeter() delegate to.
*
* Compiled only when XRPL_ENABLE_TELEMETRY is defined; the metrics API and SDK
* headers exist only in that build.
*/
#ifdef XRPL_ENABLE_TELEMETRY

View File

@@ -4,7 +4,8 @@
#include <string_view>
/** Contract tests for the transaction apply-pipeline span constants.
/**
* 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

View File

@@ -1,6 +1,7 @@
/** @file ValidationTracker.cpp
Unit tests for xrpl::telemetry::ValidationTracker.
*/
/**
* @file ValidationTracker.cpp
* Unit tests for xrpl::telemetry::ValidationTracker.
*/
#include <xrpld/telemetry/ValidationTracker.h>
@@ -17,14 +18,18 @@
using namespace xrpl;
using namespace xrpl::telemetry;
/// Helper to create a unique uint256 from an integer seed.
/**
* Helper to create a unique uint256 from an integer seed.
*/
static uint256
makeHash(std::uint64_t n)
{
return uint256(n);
}
/// Test fixture providing a fresh ValidationTracker per test.
/**
* Test fixture providing a fresh ValidationTracker per test.
*/
class ValidationTrackerTest : public ::testing::Test
{
protected:

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for ledger tracing.
/**
* Compile-time span name constants for ledger tracing.
*
* Used by BuildLedger and LedgerMaster for ledger lifecycle spans.
* Built on StaticStr/join() from SpanNames.h.
@@ -29,14 +30,18 @@ inline constexpr auto apply = makeStr("apply");
// ===== Attribute keys ========================================================
namespace attr {
/// Canonical shared constants (defined in SpanNames.h).
/**
* Canonical shared constants (defined in SpanNames.h).
*/
using ::xrpl::telemetry::attr::closeResolutionMs;
using ::xrpl::telemetry::attr::closeTime;
using ::xrpl::telemetry::attr::closeTimeCorrect;
using ::xrpl::telemetry::attr::ledgerHash;
using ::xrpl::telemetry::attr::ledgerSeq;
/// Domain-owned bare attrs.
/**
* Domain-owned bare attrs.
*/
inline constexpr auto txCount = makeStr("tx_count");
inline constexpr auto txFailed = makeStr("tx_failed");
inline constexpr auto validations = makeStr("validations");

View File

@@ -25,15 +25,16 @@ public:
group(std::string const& name) = 0;
};
/** Construct the collector manager.
@param params The [insight] config section.
@param serviceName service.name resource attribute for OTel metrics
(empty -> the collector defaults it to "xrpld").
@param networkType xrpl.network.type resource attribute for OTel
metrics (e.g. "mainnet"), derived from [network_id].
@param journal Journal for logging.
*/
/**
* Construct the collector manager.
*
* @param params The [insight] config section.
* @param serviceName service.name resource attribute for OTel metrics
* (empty -> the collector defaults it to "xrpld").
* @param networkType xrpl.network.type resource attribute for OTel
* metrics (e.g. "mainnet"), derived from [network_id].
* @param journal Journal for logging.
*/
std::unique_ptr<CollectorManager>
makeCollectorManager(
Section const& params,

View File

@@ -197,7 +197,9 @@ private:
std::vector<boost::asio::ip::address> const& secureGatewayIPs_;
/// Human-readable name for telemetry spans (e.g. "GetLedger").
/**
* Human-readable name for telemetry spans (e.g. "GetLedger").
*/
std::string_view name_;
public:

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for the gRPC subsystem.
/**
* Compile-time span name constants for the gRPC subsystem.
*
* All span prefixes, operation names, and attribute keys used by gRPC
* tracing call sites are defined here. Built on the StaticStr/join()
@@ -28,19 +29,27 @@ namespace xrpl::telemetry::grpc_span {
// ===== Span prefixes =======================================================
namespace prefix {
/// "grpc" — root prefix for gRPC transport spans. The full span name is
/// formed at the call site as `grpc.<MethodName>` (see GRPCServer.cpp).
/**
* "grpc" — root prefix for gRPC transport spans. The full span name is
* formed at the call site as `grpc.<MethodName>` (see GRPCServer.cpp).
*/
inline constexpr auto grpc = makeStr("grpc");
} // namespace prefix
// ===== Attribute keys ======================================================
namespace attr {
/// "method" — gRPC method name (e.g. GetLedger).
/**
* "method" — gRPC method name (e.g. GetLedger).
*/
inline constexpr auto method = makeStr("method");
/// "grpc_role" — Domain-qualified: collides with rpc_role.
/**
* "grpc_role" — Domain-qualified: collides with rpc_role.
*/
inline constexpr auto grpcRole = makeStr("grpc_role");
/// "grpc_status" — Domain-qualified: avoids OTel reserved span status.
/**
* "grpc_status" — Domain-qualified: avoids OTel reserved span status.
*/
inline constexpr auto grpcStatus = makeStr("grpc_status");
} // namespace attr

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for Transaction Queue tracing.
/**
* Compile-time span name constants for Transaction Queue tracing.
*
* Covers the TxQ lifecycle: enqueue decisions, direct apply, batch
* clear, ledger-close accept loop, per-tx apply, and cleanup.
@@ -55,7 +56,9 @@ namespace xrpl::telemetry::txq_span {
// ===== Span prefixes =======================================================
namespace prefix {
/// "txq" — root prefix for transaction queue spans.
/**
* "txq" — root prefix for transaction queue spans.
*/
inline constexpr auto txq = makeStr("txq");
} // namespace prefix
@@ -73,29 +76,51 @@ inline constexpr auto cleanup = makeStr("cleanup");
// ===== Attribute keys ======================================================
namespace attr {
/// Canonical shared constants (defined in SpanNames.h).
/**
* Canonical shared constants (defined in SpanNames.h).
*/
using ::xrpl::telemetry::attr::ledgerSeq;
using ::xrpl::telemetry::attr::txHash;
/// "txq_status" — domain-qualified (collides with tx_status, rpc_status).
/**
* "txq_status" — domain-qualified (collides with tx_status, rpc_status).
*/
inline constexpr auto txqStatus = makeStr("txq_status");
/// "fee_level_paid" — fee level paid by queued tx.
/**
* "fee_level_paid" — fee level paid by queued tx.
*/
inline constexpr auto feeLevelPaid = makeStr("fee_level_paid");
/// "required_fee_level" — minimum fee level for inclusion.
/**
* "required_fee_level" — minimum fee level for inclusion.
*/
inline constexpr auto requiredFeeLevel = makeStr("required_fee_level");
/// "queue_size" — current TxQ depth.
/**
* "queue_size" — current TxQ depth.
*/
inline constexpr auto queueSize = makeStr("queue_size");
/// "ledger_changed" — whether ledger changed since last attempt.
/**
* "ledger_changed" — whether ledger changed since last attempt.
*/
inline constexpr auto ledgerChanged = makeStr("ledger_changed");
/// "expired_count" — number of expired entries cleared.
/**
* "expired_count" — number of expired entries cleared.
*/
inline constexpr auto expiredCount = makeStr("expired_count");
/// "ter_code" — transaction engine result code.
/**
* "ter_code" — transaction engine result code.
*/
inline constexpr auto terCode = makeStr("ter_code");
/// "retries_remaining" — retries left before discard.
/**
* "retries_remaining" — retries left before discard.
*/
inline constexpr auto retriesRemaining = makeStr("retries_remaining");
/// "num_cleared" — entries cleared in batch.
/**
* "num_cleared" — entries cleared in batch.
*/
inline constexpr auto numCleared = makeStr("num_cleared");
/// "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
/**
* "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
*/
inline constexpr auto txType = makeStr("tx_type");
} // namespace attr

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for consensus tracing.
/**
* Compile-time span name constants for consensus tracing.
*
* Used by RCLConsensus (app), Consensus.h (template), and PeerImp
* (overlay) for consensus lifecycle spans.
@@ -125,9 +126,11 @@ inline constexpr auto phaseOpen = join(seg::consensus, op::phaseOpen);
// ===== Attribute keys ========================================================
namespace attr {
/// Canonical shared constants (defined in SpanNames.h). `ledgerHash` and
/// `fullValidation` are shared with the peer.validation.receive span — same
/// concept, same key, distinguished by span name (not an emitter prefix).
/**
* Canonical shared constants (defined in SpanNames.h). `ledgerHash` and
* `fullValidation` are shared with the peer.validation.receive span — same
* concept, same key, distinguished by span name (not an emitter prefix).
*/
using ::xrpl::telemetry::attr::closeResolutionMs;
using ::xrpl::telemetry::attr::closeTime;
using ::xrpl::telemetry::attr::closeTimeCorrect;
@@ -135,43 +138,67 @@ using ::xrpl::telemetry::attr::fullValidation;
using ::xrpl::telemetry::attr::ledgerHash;
using ::xrpl::telemetry::attr::ledgerSeq;
/// Domain-qualified attrs (rule 5 — bare name ambiguous across domains).
/// Use `<domain>_<field>` underscore form for TraceQL ergonomics.
/**
* Domain-qualified attrs (rule 5 — bare name ambiguous across domains).
* Use `<domain>_<field>` underscore form for TraceQL ergonomics.
*/
inline constexpr auto ledgerId = makeStr("consensus_ledger_id");
inline constexpr auto mode = makeStr("consensus_mode");
inline constexpr auto round = makeStr("consensus_round");
inline constexpr auto roundId = makeStr("consensus_round_id");
/// Current phase name attached to consensus.round; updated on each
/// phase transition event (open/establish/accepted).
/**
* Current phase name attached to consensus.round; updated on each
* phase transition event (open/establish/accepted).
*/
inline constexpr auto consensusPhase = makeStr("consensus_phase");
/// Boolean flag set on consensus.check when checkConsensus reports stalled.
/**
* Boolean flag set on consensus.check when checkConsensus reports stalled.
*/
inline constexpr auto consensusStalled = makeStr("consensus_stalled");
/// Domain-owned bare attrs.
/**
* Domain-owned bare attrs.
*/
inline constexpr auto proposers = makeStr("proposers");
inline constexpr auto roundTimeMs = makeStr("round_time_ms");
inline constexpr auto proposing = makeStr("proposing");
/// Round continuity / context attrs (set on consensus.round at round start).
/**
* Round continuity / context attrs (set on consensus.round at round start).
*/
inline constexpr auto previousProposers = makeStr("previous_proposers");
inline constexpr auto previousRoundTimeMs = makeStr("previous_round_time_ms");
inline constexpr auto previousLedgerSeq = makeStr("previous_ledger_seq");
inline constexpr auto closeTimeResolutionMs = makeStr("close_time_resolution_ms");
/// Open-phase end metadata (set on consensus.phase.open before reset).
/**
* Open-phase end metadata (set on consensus.phase.open before reset).
*/
inline constexpr auto openDurationMs = makeStr("open_duration_ms");
inline constexpr auto peerPositionsAtClose = makeStr("peer_positions_at_close");
/// Ledger-close inputs.
/**
* Ledger-close inputs.
*/
inline constexpr auto txCountOpen = makeStr("tx_count_open");
/// Establish/check additional state.
/**
* Establish/check additional state.
*/
inline constexpr auto proposersFinished = makeStr("proposers_finished");
/// Accept/apply enrichment.
/**
* Accept/apply enrichment.
*/
inline constexpr auto disputesResolvedCount = makeStr("disputes_resolved_count");
/// Validation send/receive enrichment. (`full_validation` is shared — see the
/// `using` re-export above.)
/**
* Validation send/receive enrichment. (`full_validation` is shared — see the
* `using` re-export above.)
*/
inline constexpr auto validationSignTime = makeStr("validation_sign_time");
/// Receive-side hash prefixes for cross-peer correlation.
/**
* Receive-side hash prefixes for cross-peer correlation.
*/
inline constexpr auto prevLedgerPrefix = makeStr("prev_ledger_prefix");
inline constexpr auto positionHashPrefix = makeStr("position_hash_prefix");
/// "consensus_state" — domain-qualified (collides with other domains' state).
/**
* "consensus_state" — domain-qualified (collides with other domains' state).
*/
inline constexpr auto consensusState = makeStr("consensus_state");
inline constexpr auto parentCloseTime = makeStr("parent_close_time");
inline constexpr auto closeTimeSelf = makeStr("close_time_self");
@@ -185,27 +212,35 @@ inline constexpr auto haveCloseTimeConsensus = makeStr("have_close_time_consensu
inline constexpr auto agreeCount = makeStr("agree_count");
inline constexpr auto disagreeCount = makeStr("disagree_count");
inline constexpr auto thresholdPercent = makeStr("threshold_percent");
/// "consensus_result" — domain-qualified (collides with generic result).
/**
* "consensus_result" — domain-qualified (collides with generic result).
*/
inline constexpr auto consensusResult = makeStr("consensus_result");
inline constexpr auto quorum = makeStr("quorum");
inline constexpr auto traceStrategy = makeStr("trace_strategy");
inline constexpr auto modeOld = makeStr("mode_old");
inline constexpr auto modeNew = makeStr("mode_new");
/// "is_bow_out" — whether this proposal is a bow-out (resigning from round).
/**
* "is_bow_out" — whether this proposal is a bow-out (resigning from round).
*/
inline constexpr auto isBowOut = makeStr("is_bow_out");
/// Transaction/dispute attrs used in consensus accept spans.
/**
* Transaction/dispute attrs used in consensus accept spans.
*/
inline constexpr auto txId = makeStr("tx_id");
inline constexpr auto disputeOurVote = makeStr("dispute_our_vote");
inline constexpr auto disputeYays = makeStr("dispute_yays");
inline constexpr auto disputeNays = makeStr("dispute_nays");
inline constexpr auto txCount = makeStr("tx_count");
inline constexpr auto disputesCount = makeStr("disputes_count");
/// Trust flag (is the message origin a trusted UNL validator). Qualified by
/// message type, shared with the peer.{proposal,validation}.receive spans:
/// consensus.proposal.receive uses `proposal_trusted`, consensus.validation.
/// receive uses `validation_trusted`. Same concept on both emitters → same key.
/**
* Trust flag (is the message origin a trusted UNL validator). Qualified by
* message type, shared with the peer.{proposal,validation}.receive spans:
* consensus.proposal.receive uses `proposal_trusted`, consensus.validation.
* receive uses `validation_trusted`. Same concept on both emitters → same key.
*/
inline constexpr auto proposalTrusted = makeStr("proposal_trusted");
inline constexpr auto validationTrusted = makeStr("validation_trusted");
} // namespace attr
@@ -213,21 +248,29 @@ inline constexpr auto validationTrusted = makeStr("validation_trusted");
// ===== Event names ===========================================================
namespace event {
/// "dispute.resolve"
/**
* "dispute.resolve"
*/
inline constexpr auto disputeResolve = join(makeStr("dispute"), makeStr("resolve"));
/// "tx.included"
/**
* "tx.included"
*/
inline constexpr auto txIncluded = join(makeStr("tx"), makeStr("included"));
/// Phase transition events — fired on consensus.round at each transition
/// so the round-level span carries a complete timeline of phase changes,
/// including the handleWrongLedger recovery edge that re-enters Open.
/**
* Phase transition events — fired on consensus.round at each transition
* so the round-level span carries a complete timeline of phase changes,
* including the handleWrongLedger recovery edge that re-enters Open.
*/
inline constexpr auto phaseOpen = join(makeStr("phase"), makeStr("open"));
inline constexpr auto phaseEstablish = join(makeStr("phase"), makeStr("establish"));
inline constexpr auto phaseAccepted = join(makeStr("phase"), makeStr("accepted"));
inline constexpr auto phaseRecovery = join(makeStr("phase"), makeStr("recovery"));
/// Outcome events — fired on consensus.round at the establish→accepted
/// transition so the path that drove acceptance is queryable.
/**
* Outcome events — fired on consensus.round at the establish→accepted
* transition so the path that drove acceptance is queryable.
*/
inline constexpr auto outcomeYes = join(makeStr("outcome"), makeStr("yes"));
inline constexpr auto outcomeMovedOn = join(makeStr("outcome"), makeStr("moved_on"));
inline constexpr auto outcomeExpired = join(makeStr("outcome"), makeStr("expired"));

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for peer overlay tracing.
/**
* Compile-time span name constants for peer overlay tracing.
*
* Used by PeerImp for peer message handling spans (proposals,
* validations). Built on StaticStr/join() from SpanNames.h.
@@ -25,14 +26,18 @@ inline constexpr auto validationReceive = makeStr("validation.receive");
// ===== Attribute keys ========================================================
namespace attr {
/// Canonical shared constants (defined in SpanNames.h). `ledgerHash` and
/// `fullValidation` are shared with the consensus validation spans — same
/// concept, same key, told apart by span name.
/**
* Canonical shared constants (defined in SpanNames.h). `ledgerHash` and
* `fullValidation` are shared with the consensus validation spans — same
* concept, same key, told apart by span name.
*/
using ::xrpl::telemetry::attr::fullValidation;
using ::xrpl::telemetry::attr::ledgerHash;
using ::xrpl::telemetry::attr::peerId;
/// Trust flag qualified by message type, shared with consensus.*.receive.
/**
* Trust flag qualified by message type, shared with consensus.*.receive.
*/
inline constexpr auto proposalTrusted = makeStr("proposal_trusted");
inline constexpr auto validationTrusted = makeStr("validation_trusted");
} // namespace attr

View File

@@ -192,10 +192,11 @@ private:
void
processSession(std::shared_ptr<Session> const&, std::shared_ptr<JobQueue::Coro> coro);
/** Process an RPC request and write the reply to `output`.
@return false if the request resulted in an error response, true
otherwise. Lets the caller's enclosing span reflect the outcome.
*/
/**
* Process an RPC request and write the reply to `output`.
* @return false if the request resulted in an error response, true
* otherwise. Lets the caller's enclosing span reflect the outcome.
*/
bool
processRequest(
Port const& port,

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for PathFind tracing.
/**
* Compile-time span name constants for PathFind tracing.
*
* Covers the path_find and ripple_path_find RPC handlers, the
* PathRequest computation engine, and the Pathfinder graph exploration.
@@ -48,7 +49,9 @@ namespace xrpl::telemetry::pathfind_span {
// ===== Span prefixes =======================================================
namespace prefix {
/// "pathfind" — root prefix for path finding spans.
/**
* "pathfind" — root prefix for path finding spans.
*/
inline constexpr auto pathfind = makeStr("pathfind");
} // namespace prefix
@@ -68,25 +71,43 @@ inline constexpr auto discover = makeStr("discover");
// `fast` or `num_paths` that other subsystems may introduce.
namespace attr {
/// "pathfind_source_account" — originating account for path search.
/**
* "pathfind_source_account" — originating account for path search.
*/
inline constexpr auto sourceAccount = makeStr("pathfind_source_account");
/// "pathfind_dest_account" — destination account.
/**
* "pathfind_dest_account" — destination account.
*/
inline constexpr auto destAccount = makeStr("pathfind_dest_account");
/// "pathfind_fast" — whether fast pathfinding mode enabled.
/**
* "pathfind_fast" — whether fast pathfinding mode enabled.
*/
inline constexpr auto fast = makeStr("pathfind_fast");
/// "pathfind_search_level" — depth of graph exploration.
/**
* "pathfind_search_level" — depth of graph exploration.
*/
inline constexpr auto searchLevel = makeStr("pathfind_search_level");
/// "pathfind_num_paths" — total paths produced across the per-source-asset
/// loop in PathRequest::findPaths (sum of getBestPaths().size() per asset).
/**
* "pathfind_num_paths" — total paths produced across the per-source-asset
* loop in PathRequest::findPaths (sum of getBestPaths().size() per asset).
*/
inline constexpr auto numPaths = makeStr("pathfind_num_paths");
/// "pathfind_num_requests" — snapshot size of requests_ at update_all start
/// (may include weak_ptrs that subsequently expire during processing).
/**
* "pathfind_num_requests" — snapshot size of requests_ at update_all start
* (may include weak_ptrs that subsequently expire during processing).
*/
inline constexpr auto numRequests = makeStr("pathfind_num_requests");
/// "pathfind_ledger_index" — pathfind target ledger index.
/**
* "pathfind_ledger_index" — pathfind target ledger index.
*/
inline constexpr auto ledgerIndex = makeStr("pathfind_ledger_index");
/// "pathfind_dest_currency" — destination currency code.
/**
* "pathfind_dest_currency" — destination currency code.
*/
inline constexpr auto destCurrency = makeStr("pathfind_dest_currency");
/// "pathfind_num_source_assets" — candidate source assets count.
/**
* "pathfind_num_source_assets" — candidate source assets count.
*/
inline constexpr auto numSourceAssets = makeStr("pathfind_num_source_assets");
} // namespace attr

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for the RPC subsystem.
/**
* Compile-time span name constants for the RPC subsystem.
*
* All span prefixes, operation names, and attribute keys used by RPC
* tracing call sites are defined here. Built on the StaticStr/join()
@@ -116,9 +117,13 @@ namespace xrpl::telemetry::rpc_span {
// ===== Span prefixes =======================================================
namespace prefix {
/// "rpc" — root prefix for transport-level spans.
/**
* "rpc" — root prefix for transport-level spans.
*/
inline constexpr auto rpc = seg::rpc;
/// "rpc.command" — prefix for individual RPC command spans.
/**
* "rpc.command" — prefix for individual RPC command spans.
*/
inline constexpr auto command = join(seg::rpc, makeStr("command"));
} // namespace prefix
@@ -134,21 +139,37 @@ inline constexpr auto process = makeStr("process");
// ===== Attribute keys ======================================================
namespace attr {
/// "command" — RPC method name.
/**
* "command" — RPC method name.
*/
inline constexpr auto command = makeStr("command");
/// "version" — api_version per request.
/**
* "version" — api_version per request.
*/
inline constexpr auto version = makeStr("version");
/// "rpc_role" — admin|user. Domain-qualified: collides with grpc_role.
/**
* "rpc_role" — admin|user. Domain-qualified: collides with grpc_role.
*/
inline constexpr auto rpcRole = makeStr("rpc_role");
/// "rpc_status" — success|error. Domain-qualified: avoids OTel reserved span status.
/**
* "rpc_status" — success|error. Domain-qualified: avoids OTel reserved span status.
*/
inline constexpr auto rpcStatus = makeStr("rpc_status");
/// "request_payload_size" — bytes of inbound request payload.
/**
* "request_payload_size" — bytes of inbound request payload.
*/
inline constexpr auto requestPayloadSize = makeStr("request_payload_size");
/// "is_batch" — whether request is a JSON-RPC batch.
/**
* "is_batch" — whether request is a JSON-RPC batch.
*/
inline constexpr auto isBatch = makeStr("is_batch");
/// "batch_size" — number of sub-requests in a batch.
/**
* "batch_size" — number of sub-requests in a batch.
*/
inline constexpr auto batchSize = makeStr("batch_size");
/// "load_type" — resource cost category after execution.
/**
* "load_type" — resource cost category after execution.
*/
inline constexpr auto loadType = makeStr("load_type");
} // namespace attr
@@ -160,7 +181,9 @@ using telemetry::attr_val::success;
inline constexpr auto admin = makeStr("admin");
inline constexpr auto user = makeStr("user");
inline constexpr auto unknownCommand = makeStr("unknown");
/// "invalid_json" — WS message parse failure or oversize.
/**
* "invalid_json" — WS message parse failure or oversize.
*/
inline constexpr auto invalidJson = makeStr("invalid_json");
} // namespace val

View File

@@ -1,6 +1,7 @@
#pragma once
/** Helpers for injecting trace context into protobuf messages.
/**
* Helpers for injecting trace context into protobuf messages.
*
* Bridges the gap between SpanGuard (which hides OTel types) and the
* protobuf TraceContext message used for cross-node propagation.
@@ -13,7 +14,7 @@
* | |
* injectSpanContext(span, proto)
*
* @note When XRPL_ENABLE_TELEMETRY is disabled, getTraceBytes() returns
* @note When XRPL_ENABLE_TELEMETRY is disabled, getTraceBytes() returns
* {.valid=false}, so injectSpanContext becomes a no-op with zero overhead.
*
* Usage:
@@ -25,8 +26,9 @@
* overlay.relay(txID, tx, toSkip);
* @endcode
*
* @see ConsensusReceiveTracing.h for receive-side extraction helpers.
* @see TraceContextPropagator.h for low-level OTel context serialization.
* @see ConsensusReceiveTracing.h and TxTracing.h for receive-side
* extraction helpers.
* @see TraceContextPropagator.h for low-level OTel context serialization.
*/
#include <xrpl/proto/xrpl.pb.h>
@@ -34,7 +36,8 @@
namespace xrpl::telemetry {
/** Inject trace context from an active SpanGuard into a protobuf
/**
* Inject trace context from an active SpanGuard into a protobuf
* TraceContext message for cross-node propagation.
*
* Reads the span's trace_id, span_id, and trace_flags via
@@ -42,8 +45,8 @@ namespace xrpl::telemetry {
* Safe to call from any thread that holds a reference to the span.
* No-op if the span is null or inactive.
*
* @param span The active SpanGuard whose context to propagate.
* @param proto The protobuf TraceContext to populate.
* @param span The active SpanGuard whose context to propagate.
* @param proto The protobuf TraceContext to populate.
*/
inline void
injectSpanContext(SpanGuard const& span, protocol::TraceContext& proto)

View File

@@ -1,6 +1,7 @@
#pragma once
/** Compile-time span name constants for transaction tracing.
/**
* Compile-time span name constants for transaction tracing.
*
* Used by PeerImp (overlay) and NetworkOPs (app) for transaction
* lifecycle spans. Built on StaticStr/join() from SpanNames.h.
@@ -22,7 +23,9 @@ namespace xrpl::telemetry::tx_span {
// ===== Span prefixes =======================================================
namespace prefix {
/// "tx" — root prefix for transaction lifecycle spans.
/**
* "tx" — root prefix for transaction lifecycle spans.
*/
inline constexpr auto tx = seg::tx;
} // namespace prefix
@@ -41,29 +44,51 @@ inline constexpr auto process = join(prefix::tx, op::process);
// ===== Attribute keys ======================================================
namespace attr {
/// Canonical shared constants (defined in SpanNames.h).
/**
* Canonical shared constants (defined in SpanNames.h).
*/
using ::xrpl::telemetry::attr::peerId;
using ::xrpl::telemetry::attr::txHash;
/// "local" — whether tx originated locally.
/**
* "local" — whether tx originated locally.
*/
inline constexpr auto local = makeStr("local");
/// "path" — sync or async processing path.
/**
* "path" — sync or async processing path.
*/
inline constexpr auto path = makeStr("path");
/// "suppressed" — whether tx was suppressed as duplicate.
/**
* "suppressed" — whether tx was suppressed as duplicate.
*/
inline constexpr auto suppressed = makeStr("suppressed");
/// "tx_status" — domain-qualified (collides with rpc_status, txq_status).
/**
* "tx_status" — domain-qualified (collides with rpc_status, txq_status).
*/
inline constexpr auto txStatus = makeStr("tx_status");
/// "peer_version" — version of peer that sent the tx.
/**
* "peer_version" — version of peer that sent the tx.
*/
inline constexpr auto peerVersion = makeStr("peer_version");
/// "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
/**
* "tx_type" — transaction type name (e.g., "Payment", "OfferCreate").
*/
inline constexpr auto txType = makeStr("tx_type");
/// "fee" — transaction fee in drops.
/**
* "fee" — transaction fee in drops.
*/
inline constexpr auto fee = makeStr("fee");
/// "sequence" — transaction sequence number.
/**
* "sequence" — transaction sequence number.
*/
inline constexpr auto sequence = makeStr("sequence");
/// "ter_result" — engine result code after application.
/**
* "ter_result" — engine result code after application.
*/
inline constexpr auto terResult = makeStr("ter_result");
/// "applied" — whether the transaction was applied to the ledger.
/**
* "applied" — whether the transaction was applied to the ledger.
*/
inline constexpr auto applied = makeStr("applied");
} // namespace attr
@@ -73,16 +98,24 @@ namespace val {
inline constexpr auto sync = makeStr("sync");
inline constexpr auto async = makeStr("async");
inline constexpr auto knownBad = makeStr("known_bad");
/// Transaction was suppressed via HashRouter (duplicate, not flagged bad).
/**
* Transaction was suppressed via HashRouter (duplicate, not flagged bad).
*/
inline constexpr auto suppressed = makeStr("suppressed");
/// Transaction was rejected because it carried tfInnerBatchTxn, which
/// must never appear in network-relayed traffic.
/**
* Transaction was rejected because it carried tfInnerBatchTxn, which
* must never appear in network-relayed traffic.
*/
inline constexpr auto rejectedInnerBatch = makeStr("rejected_inner_batch");
/// Transaction was dropped because the validated ledger is too old to
/// confidently apply new transactions (server is out of sync).
/**
* Transaction was dropped because the validated ledger is too old to
* confidently apply new transactions (server is out of sync).
*/
inline constexpr auto droppedNoSync = makeStr("dropped_no_sync");
/// Transaction was dropped because the local job queue for jtTRANSACTION
/// is at MAX_TRANSACTIONS — backpressure on the receive side.
/**
* Transaction was dropped because the local job queue for jtTRANSACTION
* is at MAX_TRANSACTIONS — backpressure on the receive side.
*/
inline constexpr auto droppedQueueFull = makeStr("dropped_queue_full");
} // namespace val

View File

@@ -1,6 +1,7 @@
#pragma once
/** Helper functions for creating transaction trace spans.
/**
* Helper functions for creating transaction trace spans.
*
* Encapsulates the logic for creating SpanGuard instances with
* hash-derived trace IDs and optional protobuf parent extraction.
@@ -21,7 +22,8 @@
namespace xrpl::telemetry {
/** Create a "tx.receive" span for a transaction received from a peer.
/**
* Create a "tx.receive" span for a transaction received from a peer.
* trace_id is derived from txID[0:16]. If the incoming message carries
* a protobuf TraceContext with a valid span_id, it is used as the
* parent to preserve relay ordering.
@@ -53,7 +55,8 @@ txReceiveSpan(uint256 const& txID, [[maybe_unused]] protocol::TMTransaction cons
TraceCategory::Transactions, tx_span::receive, txID.data(), txID.kBytes);
}
/** Create a "tx.process" span for transaction processing in NetworkOPs.
/**
* Create a "tx.process" span for transaction processing in NetworkOPs.
* trace_id is derived from txID[0:16].
*/
inline SpanGuard

View File

@@ -1,8 +1,9 @@
#pragma once
/** @file ValidationTracker.h
Standalone validation agreement tracker for telemetry.
*/
/**
* @file ValidationTracker.h
* Standalone validation agreement tracker for telemetry.
*/
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h>
@@ -93,10 +94,14 @@ namespace xrpl::telemetry {
class ValidationTracker
{
public:
/// Monotonic clock used for all internal timestamps.
/**
* Monotonic clock used for all internal timestamps.
*/
using Clock = std::chrono::steady_clock;
/// Time point type from the monotonic clock.
/**
* Time point type from the monotonic clock.
*/
using TimePoint = Clock::time_point;
/**
@@ -124,74 +129,103 @@ public:
void
reconcile();
/** @name Rolling-window percentage getters */
/**
* @name Rolling-window percentage getters
*/
/** @{ */
/** Agreement percentage over the last 1 hour.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
/**
* Agreement percentage over the last 1 hour.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
*/
double
agreementPct1h() const;
/** Agreement percentage over the last 24 hours.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
/**
* Agreement percentage over the last 24 hours.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
*/
double
agreementPct24h() const;
/** Agreement percentage over the last 7 days.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
/**
* Agreement percentage over the last 7 days.
* @return Percentage [0.0, 100.0], or 0.0 if no data.
*/
double
agreementPct7d() const;
/** @} */
/** @name Rolling-window count getters */
/**
* @name Rolling-window count getters
*/
/** @{ */
/** Number of agreements in the 1-hour window. */
/**
* Number of agreements in the 1-hour window.
*/
uint64_t
agreements1h() const;
/** Number of misses in the 1-hour window. */
/**
* Number of misses in the 1-hour window.
*/
uint64_t
missed1h() const;
/** Number of agreements in the 24-hour window. */
/**
* Number of agreements in the 24-hour window.
*/
uint64_t
agreements24h() const;
/** Number of misses in the 24-hour window. */
/**
* Number of misses in the 24-hour window.
*/
uint64_t
missed24h() const;
/** Number of agreements in the 7-day window. */
/**
* Number of agreements in the 7-day window.
*/
uint64_t
agreements7d() const;
/** Number of misses in the 7-day window. */
/**
* Number of misses in the 7-day window.
*/
uint64_t
missed7d() const;
/** @} */
/** @name Lifetime totals (atomic, lock-free reads) */
/**
* @name Lifetime totals (atomic, lock-free reads)
*/
/** @{ */
/** Total agreements since process start. */
/**
* Total agreements since process start.
*/
uint64_t
totalAgreements() const;
/** Total misses since process start. */
/**
* Total misses since process start.
*/
uint64_t
totalMissed() const;
/** Total validations this node sent. */
/**
* Total validations this node sent.
*/
uint64_t
totalValidationsSent() const;
/** Total network validations observed for comparison. */
/**
* Total network validations observed for comparison.
*/
uint64_t
totalValidationsChecked() const;
@@ -222,49 +256,79 @@ private:
bool agreed{false}; ///< Whether this was an agreement.
};
/// Grace period before reconciling a ledger event.
/**
* Grace period before reconciling a ledger event.
*/
static constexpr auto kGracePeriod = std::chrono::seconds(8);
/// Window during which a missed event can be repaired.
/**
* Window during which a missed event can be repaired.
*/
static constexpr auto kLateRepairWindow = std::chrono::minutes(5);
/// Maximum number of pending (unreconciled + recently reconciled) events.
/**
* Maximum number of pending (unreconciled + recently reconciled) events.
*/
static constexpr std::size_t kMaxPendingEvents = 1000;
/// Duration of the short rolling window.
/**
* Duration of the short rolling window.
*/
static constexpr auto kWindow1h = std::chrono::hours(1);
/// Duration of the long rolling window.
/**
* Duration of the long rolling window.
*/
static constexpr auto kWindow24h = std::chrono::hours(24);
/// Duration of the extended rolling window (7 days).
/**
* Duration of the extended rolling window (7 days).
*/
static constexpr auto kWindow7d = std::chrono::hours(168);
/// Protects pending_, window1h_, window24h_, and window7d_.
/**
* Protects pending_, window1h_, window24h_, and window7d_.
*/
mutable std::mutex mutex_;
/// Pending ledger events indexed by ledger hash.
/**
* Pending ledger events indexed by ledger hash.
*/
hash_map<uint256, LedgerEvent> pending_;
/// Sliding window of reconciled events (last 1 hour).
/**
* Sliding window of reconciled events (last 1 hour).
*/
std::deque<WindowEvent> window1h_;
/// Sliding window of reconciled events (last 24 hours).
/**
* Sliding window of reconciled events (last 24 hours).
*/
std::deque<WindowEvent> window24h_;
/// Sliding window of reconciled events (last 7 days).
/**
* Sliding window of reconciled events (last 7 days).
*/
std::deque<WindowEvent> window7d_;
/// Lifetime count of agreements.
/**
* Lifetime count of agreements.
*/
std::atomic<uint64_t> totalAgreements_{0};
/// Lifetime count of misses.
/**
* Lifetime count of misses.
*/
std::atomic<uint64_t> totalMissed_{0};
/// Lifetime count of validations this node sent.
/**
* Lifetime count of validations this node sent.
*/
std::atomic<uint64_t> totalValidationsSent_{0};
/// Lifetime count of network validations observed.
/**
* Lifetime count of network validations observed.
*/
std::atomic<uint64_t> totalValidationsChecked_{0};
/**

View File

@@ -1,6 +1,7 @@
/** @file ValidationTracker.cpp
Implementation of the ValidationTracker class.
*/
/**
* @file ValidationTracker.cpp
* Implementation of the ValidationTracker class.
*/
#include <xrpld/telemetry/ValidationTracker.h>