diff --git a/include/xrpl/telemetry/SpanNames.h b/include/xrpl/telemetry/SpanNames.h index 3c8b6144f9..9fdc37cd64 100644 --- a/include/xrpl/telemetry/SpanNames.h +++ b/include/xrpl/telemetry/SpanNames.h @@ -20,6 +20,7 @@ * - Per-span attribute keys: bare field name (span name carries the domain). * - Collision qualifier: _ when bare name collides across * domains or with OTel reserved `status` (e.g. rpc_status, grpc_status). + * - Shared cross-span attributes: _ (underscore) form. * - Resource attribute keys: xrpl.. (process-identity). * - Span prefixes: [.]. */ diff --git a/include/xrpl/telemetry/Telemetry.h b/include/xrpl/telemetry/Telemetry.h index f648289569..0cb217bd29 100644 --- a/include/xrpl/telemetry/Telemetry.h +++ b/include/xrpl/telemetry/Telemetry.h @@ -3,13 +3,15 @@ /** Abstract interface for OpenTelemetry distributed tracing. Provides the Telemetry base class that all components use to create trace - spans. Two concrete implementations exist, selected at construction time + spans. Three concrete implementations exist, selected at construction time by make_Telemetry(): - 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: @@ -37,32 +39,33 @@ 1. Root span at a subsystem entry point (typical usage): @code + #include + using namespace xrpl::telemetry; + // In an RPC handler dispatch: - auto guard = SpanGuard::span(TraceCategory::Rpc, "rpc", commandName); - guard.setAttribute("xrpl.rpc.command", commandName); + 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 (cross-scope): - @code - auto parent = SpanGuard::span(TraceCategory::Transactions, "tx", "process"); - { - SpanGuard guard(telemetry.startSpan("rpc.command.submit")); - guard.setAttribute("command", "submit"); - // ... guard ends span automatically on scope exit - } - @endcode - - 3. Child span for a sub-operation (cross-scope): + 2. Child span for a sub-operation (scoped child): @code auto parent = SpanGuard::span(TraceCategory::Transactions, "tx", "process"); { auto child = parent.childSpan("tx.apply"); - child.setAttribute("xrpl.tx.type", txType); + child.setAttribute("tx_type", txType); // child ends here } - // parent continues, then ends here + @endcode + + 3. Unrelated span (cross-scope, same thread): + @code + // Transactions and RPC can be active simultaneously + auto txSpan = SpanGuard::span(TraceCategory::Transactions, "tx", "process"); + auto rpcSpan = SpanGuard::span(TraceCategory::Rpc, "rpc", "info"); + // both spans end on scope exit @endcode 4. Cross-thread context propagation: diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index eeb4797b19..92760d641f 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -179,6 +179,7 @@ GRPCServerImpl::CallData::process(std::shared_ptr::process(std::shared_ptrerror, ok->success. + span.setAttribute( + rpc_span::attr::rpcStatus, ret ? rpc_span::val::error : rpc_span::val::success); + if (!ret) + span.setOk(); return ret; } catch (std::exception& e) diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index a181ec56cd..4f1918076c 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -564,6 +564,7 @@ ServerHandler::processSession( jr[jss::api_version] = jv[jss::api_version]; jr[jss::type] = jss::response; + span.setOk(); return jr; } @@ -598,6 +599,7 @@ ServerHandler::processSession( { session->close(true); } + span.setOk(); } static Json::Value @@ -1036,6 +1038,7 @@ ServerHandler::processRequest( } } + span.setOk(); HTTPReply(httpStatus, response, output, rpcJ); }