From 27ef26d231bf3ac391abbf05ed60bdf67eb4dbcd Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Thu, 27 Aug 2026 13:55:20 +0100 Subject: [PATCH] docs(telemetry): say what the compiled-out path actually costs The conditional-compilation section promised zero overhead when telemetry is not wanted. The span disappears, but the arguments passed to it do not: the compiled-out guards are ordinary inline functions, so a to_string() or a hash in an argument list still runs and its result is then discarded. State that, show the guard that does remove the work, and name the opposite case -- the metric macros, which discard their arguments and need no guard. --- docs/build/telemetry.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/build/telemetry.md b/docs/build/telemetry.md index eca4e9f110..14f40c355b 100644 --- a/docs/build/telemetry.md +++ b/docs/build/telemetry.md @@ -126,12 +126,26 @@ The Conan package provides a single umbrella target ## Conditional compilation -All OpenTelemetry SDK types are hidden behind the pimpl idiom in `SpanGuard.cpp`. -When `XRPL_ENABLE_TELEMETRY` is not defined, `SpanGuard.h` provides an all-inline -no-op stub class with zero overhead and zero OTel dependencies. -At runtime, if `enabled=0` is set in config (or the section is omitted), a -`NullTelemetry` implementation is used that returns no-op spans. -This two-layer approach ensures zero overhead when telemetry is not wanted. +All OpenTelemetry SDK types are hidden behind the pimpl idiom in `SpanGuard.cpp`. When `XRPL_ENABLE_TELEMETRY` is not defined, `SpanGuard.h` provides an all-inline no-op stub class with no OTel dependencies. At runtime, if `enabled=0` is set in config (or the section is omitted), a `NullTelemetry` implementation is used that returns no-op spans. + +Those two layers remove the span, but they do **not** remove the work that computes what you pass to it. The compiled-out guards are ordinary inline functions with ordinary parameters, so every argument is evaluated before the empty body is entered: + +```cpp +// to_string() allocates a 64-character string even in a build with telemetry +// compiled out. The call then does nothing with it. +span.setAttribute(attr::txHash, to_string(txID).c_str()); +``` + +Guard the work, not just the call. Testing the guard is enough: its `operator bool()` is a literal `false` when telemetry is compiled out, so the whole block is eliminated, and when telemetry is compiled in it also skips the work if tracing is switched off in config or the span's category is disabled. + +```cpp +if (span) + span.setAttribute(attr::txHash, to_string(txID).c_str()); +``` + +A span that exists but was sampled out still pays: there is no `isRecording()` to test. + +The `XRPL_METRIC_*` macros are the opposite case. They expand to `do { } while (false)` and discard their arguments, so anything named only inside a macro argument list disappears on its own and needs no guard. ## Span lifetime and cross-thread handling