diff --git a/src/libxrpl/telemetry/Telemetry.cpp b/src/libxrpl/telemetry/Telemetry.cpp index a7ba3a4a11..8076146a9c 100644 --- a/src/libxrpl/telemetry/Telemetry.cpp +++ b/src/libxrpl/telemetry/Telemetry.cpp @@ -20,10 +20,12 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -263,6 +265,13 @@ class TelemetryImpl : public Telemetry */ std::shared_ptr sdkProvider_; + /** + * Coroutine-aware runtime-context storage, installed globally so the OTel + * ambient context follows JobQueue coroutines. Held for the process + * lifetime because it must outlive every span (SDK requirement). + */ + opentelemetry::nostd::shared_ptr contextStorage_; + public: TelemetryImpl(Setup setup, beast::Journal journal) : setup_(std::move(setup)), journal_(journal) { @@ -332,6 +341,18 @@ public: std::move(sampler), std::make_unique()); + // Install coroutine-aware context storage BEFORE any span is created + // so the OTel ambient context follows JobQueue coroutines across + // yield/resume (fixes wrong-thread scope pop; keeps log-trace + // correlation). Must precede SetTracerProvider and the first span. + // Not reset in stop(): resetting the storage while spans may still + // exist is undefined behaviour (SDK), and by stop() all spans are + // gone, so the storage is simply left installed for process lifetime. + contextStorage_ = + opentelemetry::nostd::shared_ptr( + new CoroAwareContextStorage()); + opentelemetry::context::RuntimeContext::SetRuntimeContextStorage(contextStorage_); + // Set as global provider trace_api::Provider::SetTracerProvider( opentelemetry::nostd::shared_ptr(sdkProvider_));