mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
feat(telemetry): replace tracing macros with SpanGuard factory pattern
Delete TracingInstrumentation.h and replace all XRPL_TRACE_* macro invocations with direct SpanGuard::rpcSpan() calls. SpanGuard's pimpl design and global Telemetry accessor eliminate the need for macro wrappers and explicit Telemetry instance passing at call sites. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -119,7 +119,7 @@ endif()
|
||||
|
||||
# OpenTelemetry distributed tracing (optional).
|
||||
# When ON, links against opentelemetry-cpp and defines XRPL_ENABLE_TELEMETRY
|
||||
# so that tracing macros in TracingInstrumentation.h are compiled in.
|
||||
# so that SpanGuard factory methods produce real OTel spans.
|
||||
# When OFF (default), all tracing code compiles to no-ops with zero overhead.
|
||||
# Enable via: conan install -o telemetry=True, or cmake -Dtelemetry=ON.
|
||||
option(telemetry "Enable OpenTelemetry tracing" OFF)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xrpld/rpc/Status.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
#include <xrpld/rpc/detail/Tuning.h>
|
||||
#include <xrpld/telemetry/TracingInstrumentation.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/core/Job.h>
|
||||
@@ -17,6 +16,9 @@
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/resource/Fees.h>
|
||||
#include <xrpl/server/InfoSub.h>
|
||||
#include <xrpl/server/NetworkOPs.h>
|
||||
#include <xrpl/telemetry/SpanGuard.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@@ -158,10 +160,10 @@ template <class Object, class Method>
|
||||
Status
|
||||
callMethod(JsonContext& context, Method method, std::string const& name, Object& result)
|
||||
{
|
||||
XRPL_TRACE_RPC(context.app.getTelemetry(), "rpc.command." + name);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.command", name.c_str());
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.version", static_cast<int64_t>(context.apiVersion));
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.role", (context.role == Role::ADMIN ? "admin" : "user"));
|
||||
auto span = telemetry::SpanGuard::rpcSpan("rpc.command." + name);
|
||||
span.setAttribute("xrpl.rpc.command", name.c_str());
|
||||
span.setAttribute("xrpl.rpc.version", static_cast<int64_t>(context.apiVersion));
|
||||
span.setAttribute("xrpl.rpc.role", (context.role == Role::ADMIN ? "admin" : "user"));
|
||||
|
||||
static std::atomic<std::uint64_t> requestId{0};
|
||||
auto& perfLog = context.app.getPerfLog();
|
||||
@@ -178,15 +180,15 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object&
|
||||
JLOG(context.j.debug()) << "RPC call " << name << " completed in "
|
||||
<< ((end - start).count() / 1000000000.0) << "seconds";
|
||||
perfLog.rpcFinish(name, curId);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "success");
|
||||
span.setAttribute("xrpl.rpc.status", "success");
|
||||
return ret;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
perfLog.rpcError(name, curId);
|
||||
JLOG(context.j.info()) << "Caught throw: " << e.what();
|
||||
XRPL_TRACE_EXCEPTION(e);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "error");
|
||||
span.recordException(e);
|
||||
span.setAttribute("xrpl.rpc.status", "error");
|
||||
|
||||
if (context.loadType == Resource::feeReferenceRPC)
|
||||
context.loadType = Resource::feeExceptionRPC;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <xrpld/rpc/detail/Tuning.h>
|
||||
#include <xrpld/rpc/detail/WSInfoSub.h>
|
||||
#include <xrpld/rpc/json_body.h>
|
||||
#include <xrpld/telemetry/TracingInstrumentation.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base64.h>
|
||||
@@ -45,6 +44,7 @@
|
||||
#include <xrpl/server/SimpleWriter.h>
|
||||
#include <xrpl/server/WSSession.h>
|
||||
#include <xrpl/server/detail/JSONRPCUtil.h>
|
||||
#include <xrpl/telemetry/SpanGuard.h>
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
@@ -418,7 +418,7 @@ ServerHandler::processSession(
|
||||
std::shared_ptr<JobQueue::Coro> const& coro,
|
||||
Json::Value const& jv)
|
||||
{
|
||||
XRPL_TRACE_RPC(app_.getTelemetry(), "rpc.ws_message");
|
||||
auto span = telemetry::SpanGuard::rpcSpan("rpc.ws_message");
|
||||
auto is = std::static_pointer_cast<WSInfoSub>(session->appDefined);
|
||||
if (is->getConsumer().disconnect(m_journal))
|
||||
{
|
||||
@@ -502,8 +502,8 @@ ServerHandler::processSession(
|
||||
jr[jss::result] = RPC::make_error(rpcINTERNAL);
|
||||
JLOG(m_journal.error()) << "Exception while processing WS: " << ex.what() << "\n"
|
||||
<< "Input JSON: " << Json::Compact{Json::Value{jv}};
|
||||
XRPL_TRACE_EXCEPTION(ex);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "error");
|
||||
span.recordException(ex);
|
||||
span.setAttribute("xrpl.rpc.status", "error");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -563,7 +563,7 @@ ServerHandler::processSession(
|
||||
std::shared_ptr<Session> const& session,
|
||||
std::shared_ptr<JobQueue::Coro> coro)
|
||||
{
|
||||
XRPL_TRACE_RPC(app_.getTelemetry(), "rpc.http_request");
|
||||
auto span = telemetry::SpanGuard::rpcSpan("rpc.http_request");
|
||||
|
||||
processRequest(
|
||||
session->port(),
|
||||
@@ -615,7 +615,7 @@ ServerHandler::processRequest(
|
||||
std::string_view forwardedFor,
|
||||
std::string_view user)
|
||||
{
|
||||
XRPL_TRACE_RPC(app_.getTelemetry(), "rpc.process");
|
||||
auto span = telemetry::SpanGuard::rpcSpan("rpc.process");
|
||||
auto rpcJ = app_.getJournal("RPC");
|
||||
|
||||
Json::Value jsonOrig;
|
||||
@@ -892,8 +892,8 @@ ServerHandler::processRequest(
|
||||
JLOG(m_journal.error())
|
||||
<< "Internal error : " << ex.what()
|
||||
<< " when processing request: " << Json::Compact{Json::Value{params}};
|
||||
XRPL_TRACE_EXCEPTION(ex);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "error");
|
||||
span.recordException(ex);
|
||||
span.setAttribute("xrpl.rpc.status", "error");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/** Convenience macros for instrumenting code with OpenTelemetry trace spans.
|
||||
|
||||
When XRPL_ENABLE_TELEMETRY is defined, the macros create SpanGuard objects
|
||||
that manage span lifetime via RAII. When not defined, all macros expand to
|
||||
((void)0) with zero overhead.
|
||||
|
||||
All span-creation macros produce a std::optional<SpanGuard> named
|
||||
_xrpl_guard_. The accessor macros (XRPL_TRACE_SET_ATTR,
|
||||
XRPL_TRACE_EXCEPTION) reference this variable by name, so they must
|
||||
appear in the same scope after exactly one span-creation macro.
|
||||
|
||||
@note Only one XRPL_TRACE_* span-creation macro may appear per scope,
|
||||
because they all declare a variable named _xrpl_guard_. Nested spans
|
||||
across function boundaries are fine (each function has its own scope).
|
||||
|
||||
@note These macros must not be used in single-statement if/else without
|
||||
braces. The span-creation macros expand to multiple statements that
|
||||
declare variables needed by the accessor macros.
|
||||
|
||||
@note Thread safety: Each SpanGuard binds to the constructing thread's
|
||||
OTel context stack via Scope. Do not move a guard across threads.
|
||||
|
||||
Usage examples:
|
||||
|
||||
1. Basic RPC tracing:
|
||||
@code
|
||||
XRPL_TRACE_RPC(app.getTelemetry(), "rpc.command." + name);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.command", name);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "success");
|
||||
@endcode
|
||||
|
||||
2. Exception recording:
|
||||
@code
|
||||
XRPL_TRACE_RPC(telemetry, "rpc.process");
|
||||
try {
|
||||
doWork();
|
||||
} catch (std::exception const& e) {
|
||||
XRPL_TRACE_EXCEPTION(e);
|
||||
XRPL_TRACE_SET_ATTR("xrpl.rpc.status", "error");
|
||||
}
|
||||
@endcode
|
||||
|
||||
3. Unconditional span:
|
||||
@code
|
||||
XRPL_TRACE_SPAN(telemetry, "tx.apply");
|
||||
XRPL_TRACE_SET_ATTR("xrpl.tx.hash", txHash);
|
||||
@endcode
|
||||
*/
|
||||
|
||||
#ifdef XRPL_ENABLE_TELEMETRY
|
||||
|
||||
#include <xrpl/telemetry/SpanGuard.h>
|
||||
#include <xrpl/telemetry/Telemetry.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
/** Start an unconditional span, ended when the guard goes out of scope.
|
||||
@param _tel_obj_ Telemetry instance reference.
|
||||
@param _span_name_ Span name string.
|
||||
*/
|
||||
#define XRPL_TRACE_SPAN(_tel_obj_, _span_name_) \
|
||||
std::optional<::xrpl::telemetry::SpanGuard> _xrpl_guard_( \
|
||||
std::in_place, (_tel_obj_).startSpan(_span_name_))
|
||||
|
||||
/** Start an unconditional span with a specific SpanKind.
|
||||
@param _tel_obj_ Telemetry instance reference.
|
||||
@param _span_name_ Span name string.
|
||||
@param _span_kind_ opentelemetry::trace::SpanKind value.
|
||||
*/
|
||||
#define XRPL_TRACE_SPAN_KIND(_tel_obj_, _span_name_, _span_kind_) \
|
||||
std::optional<::xrpl::telemetry::SpanGuard> _xrpl_guard_( \
|
||||
std::in_place, (_tel_obj_).startSpan(_span_name_, _span_kind_))
|
||||
|
||||
/** Conditionally start a span for RPC tracing.
|
||||
The span is only created if shouldTraceRpc() returns true.
|
||||
@param _tel_obj_ Telemetry instance reference.
|
||||
@param _span_name_ Span name string.
|
||||
*/
|
||||
#define XRPL_TRACE_RPC(_tel_obj_, _span_name_) \
|
||||
auto& _xrpl_tel_ = (_tel_obj_); \
|
||||
std::optional<::xrpl::telemetry::SpanGuard> _xrpl_guard_; \
|
||||
if (_xrpl_tel_.shouldTraceRpc()) \
|
||||
{ \
|
||||
_xrpl_guard_.emplace(_xrpl_tel_.startSpan(_span_name_)); \
|
||||
}
|
||||
|
||||
/** Conditionally start a span for transaction tracing.
|
||||
The span is only created if shouldTraceTransactions() returns true.
|
||||
@param _tel_obj_ Telemetry instance reference.
|
||||
@param _span_name_ Span name string.
|
||||
*/
|
||||
#define XRPL_TRACE_TX(_tel_obj_, _span_name_) \
|
||||
auto& _xrpl_tel_ = (_tel_obj_); \
|
||||
std::optional<::xrpl::telemetry::SpanGuard> _xrpl_guard_; \
|
||||
if (_xrpl_tel_.shouldTraceTransactions()) \
|
||||
{ \
|
||||
_xrpl_guard_.emplace(_xrpl_tel_.startSpan(_span_name_)); \
|
||||
}
|
||||
|
||||
/** Conditionally start a span for consensus tracing.
|
||||
The span is only created if shouldTraceConsensus() returns true.
|
||||
@param _tel_obj_ Telemetry instance reference.
|
||||
@param _span_name_ Span name string.
|
||||
*/
|
||||
#define XRPL_TRACE_CONSENSUS(_tel_obj_, _span_name_) \
|
||||
auto& _xrpl_tel_ = (_tel_obj_); \
|
||||
std::optional<::xrpl::telemetry::SpanGuard> _xrpl_guard_; \
|
||||
if (_xrpl_tel_.shouldTraceConsensus()) \
|
||||
{ \
|
||||
_xrpl_guard_.emplace(_xrpl_tel_.startSpan(_span_name_)); \
|
||||
}
|
||||
|
||||
/** Set a key-value attribute on the current span (if it exists).
|
||||
Must be used after one of the XRPL_TRACE_* span-creation macros
|
||||
in the same scope.
|
||||
*/
|
||||
#define XRPL_TRACE_SET_ATTR(key, value) \
|
||||
do \
|
||||
{ \
|
||||
if (_xrpl_guard_.has_value()) \
|
||||
_xrpl_guard_->setAttribute(key, value); \
|
||||
} while (0)
|
||||
|
||||
/** Record an exception on the current span and mark it as error.
|
||||
Must be used after one of the XRPL_TRACE_* span-creation macros
|
||||
in the same scope.
|
||||
*/
|
||||
#define XRPL_TRACE_EXCEPTION(e) \
|
||||
do \
|
||||
{ \
|
||||
if (_xrpl_guard_.has_value()) \
|
||||
_xrpl_guard_->recordException(e); \
|
||||
} while (0)
|
||||
|
||||
#else // XRPL_ENABLE_TELEMETRY not defined
|
||||
|
||||
#define XRPL_TRACE_SPAN(_tel_obj_, _span_name_) ((void)0)
|
||||
#define XRPL_TRACE_SPAN_KIND(_tel_obj_, _span_name_, _span_kind_) ((void)0)
|
||||
#define XRPL_TRACE_RPC(_tel_obj_, _span_name_) ((void)0)
|
||||
#define XRPL_TRACE_TX(_tel_obj_, _span_name_) ((void)0)
|
||||
#define XRPL_TRACE_CONSENSUS(_tel_obj_, _span_name_) ((void)0)
|
||||
#define XRPL_TRACE_SET_ATTR(key, value) ((void)0)
|
||||
#define XRPL_TRACE_EXCEPTION(e) ((void)0)
|
||||
|
||||
#endif // XRPL_ENABLE_TELEMETRY
|
||||
Reference in New Issue
Block a user