diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/zenhttp/httpserver.cpp | 56 | ||||
| -rw-r--r-- | src/zenhttp/include/zenhttp/httpserver.h | 7 | ||||
| -rw-r--r-- | src/zenhttp/servers/httpasio.cpp | 3 | ||||
| -rw-r--r-- | src/zenhttp/servers/httpplugin.cpp | 3 | ||||
| -rw-r--r-- | src/zenhttp/servers/httpsys.cpp | 93 | ||||
| -rw-r--r-- | src/zenserver-test/buildstore-tests.cpp | 2 | ||||
| -rw-r--r-- | src/zenserver/main.cpp | 3 | ||||
| -rw-r--r-- | src/zenserver/storage/zenstorageserver.cpp | 12 | ||||
| -rw-r--r-- | src/zenserver/zenserver.cpp | 4 | ||||
| -rw-r--r-- | src/zenstore/gc.cpp | 6 | ||||
| -rw-r--r-- | src/zenstore/xmake.lua | 2 | ||||
| -rw-r--r-- | src/zentelemetry/include/zentelemetry/otlptrace.h | 41 | ||||
| -rw-r--r-- | src/zentelemetry/otlptrace.cpp | 60 |
13 files changed, 237 insertions, 55 deletions
diff --git a/src/zenhttp/httpserver.cpp b/src/zenhttp/httpserver.cpp index e529fb76e..085275195 100644 --- a/src/zenhttp/httpserver.cpp +++ b/src/zenhttp/httpserver.cpp @@ -26,6 +26,7 @@ #include <zencore/testing.h> #include <zencore/thread.h> #include <zenhttp/packageformat.h> +#include <zentelemetry/otlptrace.h> #include <charconv> #include <mutex> @@ -462,7 +463,7 @@ HttpService::HandlePackageRequest(HttpServerRequest& HttpServiceRequest) ////////////////////////////////////////////////////////////////////////// -HttpServerRequest::HttpServerRequest() +HttpServerRequest::HttpServerRequest(HttpService& Service) : m_BaseUri(Service.BaseUri()) { } @@ -896,7 +897,7 @@ HttpRequestRouter::HandleRequest(zen::HttpServerRequest& Request) // First try new-style matcher routes - for (const auto& Handler : m_MatcherEndpoints) + for (const MatcherEndpoint& Handler : m_MatcherEndpoints) { if ((Handler.Verbs & Verb) == Verb) { @@ -965,6 +966,16 @@ HttpRequestRouter::HandleRequest(zen::HttpServerRequest& Request) if (IsMatch && UriPos == UriLen) { +#if ZEN_WITH_OTEL + if (otel::Span* ActiveSpan = otel::Span::GetCurrentSpan()) + { + ExtendableStringBuilder<128> RoutePath; + RoutePath.Append(Request.BaseUri()); + RoutePath.Append(Handler.Pattern); + ActiveSpan->AddAttribute("http.route"sv, RoutePath.ToView()); + } +#endif + RouterRequest.m_CapturedSegments = std::move(CapturedSegments); Handler.Handler(RouterRequest); @@ -979,6 +990,16 @@ HttpRequestRouter::HandleRequest(zen::HttpServerRequest& Request) { if ((Handler.Verbs & Verb) == Verb && regex_match(begin(Uri), end(Uri), RouterRequest.m_Match, Handler.RegEx)) { +#if ZEN_WITH_OTEL + if (otel::Span* ActiveSpan = otel::Span::GetCurrentSpan()) + { + ExtendableStringBuilder<128> RoutePath; + RoutePath.Append(Request.BaseUri()); + RoutePath.Append(Handler.Pattern); + ActiveSpan->AddAttribute("http.route"sv, RoutePath.ToView()); + } +#endif + Handler.Handler(RouterRequest); return true; // Route matched @@ -1277,9 +1298,17 @@ TEST_CASE("http.common") { using namespace std::literals; + struct TestHttpService : public HttpService + { + TestHttpService() = default; + + virtual const char* BaseUri() const override { return "/test"; } + virtual void HandleRequest(HttpServerRequest& HttpServiceRequest) override { ZEN_UNUSED(HttpServiceRequest); } + }; + struct TestHttpServerRequest : public HttpServerRequest { - TestHttpServerRequest(std::string_view Uri) { m_Uri = Uri; } + TestHttpServerRequest(HttpService& Service, std::string_view Uri) : HttpServerRequest(Service) { m_Uri = Uri; } virtual IoBuffer ReadPayload() override { return IoBuffer(); } virtual void WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs) override { @@ -1308,6 +1337,8 @@ TEST_CASE("http.common") HandledA = HandledAA = false; }; + TestHttpService Service; + HttpRequestRouter r; r.AddPattern("a", "([[:alpha:]]+)"); r.RegisterRoute( @@ -1328,7 +1359,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"abc"sv}; + TestHttpServerRequest req(Service, "abc"sv); r.HandleRequest(req); CHECK(HandledA); CHECK(!HandledAA); @@ -1338,7 +1369,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"abc/def"sv}; + TestHttpServerRequest req{Service, "abc/def"sv}; r.HandleRequest(req); CHECK(!HandledA); CHECK(HandledAA); @@ -1349,14 +1380,14 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"123"sv}; + TestHttpServerRequest req{Service, "123"sv}; r.HandleRequest(req); CHECK(!HandledA); } { Reset(); - TestHttpServerRequest req{"a123"sv}; + TestHttpServerRequest req{Service, "a123"sv}; r.HandleRequest(req); CHECK(!HandledA); } @@ -1374,6 +1405,7 @@ TEST_CASE("http.common") Captures.clear(); }; + TestHttpService Service; HttpRequestRouter r; r.AddMatcher("a", [](std::string_view In) -> bool { return In.length() % 2 == 0; }); r.AddMatcher("b", [](std::string_view In) -> bool { return In.length() % 3 == 0; }); @@ -1408,7 +1440,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"ab"sv}; + TestHttpServerRequest req{Service, "ab"sv}; r.HandleRequest(req); CHECK(HandledA); CHECK(!HandledAA); @@ -1420,7 +1452,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"ab/def"sv}; + TestHttpServerRequest req{Service, "ab/def"sv}; r.HandleRequest(req); CHECK(!HandledA); CHECK(!HandledAA); @@ -1432,7 +1464,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"ab/and/def"sv}; + TestHttpServerRequest req{Service, "ab/and/def"sv}; r.HandleRequest(req); CHECK(!HandledA); CHECK(!HandledAA); @@ -1445,7 +1477,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"123"sv}; + TestHttpServerRequest req{Service, "123"sv}; r.HandleRequest(req); CHECK(!HandledA); CHECK(!HandledAA); @@ -1454,7 +1486,7 @@ TEST_CASE("http.common") { Reset(); - TestHttpServerRequest req{"a123"sv}; + TestHttpServerRequest req{Service, "a123"sv}; r.HandleRequest(req); CHECK(HandledA); CHECK(!HandledAA); diff --git a/src/zenhttp/include/zenhttp/httpserver.h b/src/zenhttp/include/zenhttp/httpserver.h index 9e5c41ab7..074e40734 100644 --- a/src/zenhttp/include/zenhttp/httpserver.h +++ b/src/zenhttp/include/zenhttp/httpserver.h @@ -24,13 +24,14 @@ namespace zen { class CbPackage; +class HttpService; /** HTTP Server Request */ class HttpServerRequest { public: - HttpServerRequest(); + explicit HttpServerRequest(HttpService& Service); ~HttpServerRequest(); // Synchronous operations @@ -38,6 +39,7 @@ public: [[nodiscard]] inline std::string_view RelativeUri() const { return m_Uri; } // Returns URI without service prefix [[nodiscard]] std::string_view RelativeUriWithExtension() const { return m_UriWithExtension; } [[nodiscard]] inline std::string_view QueryString() const { return m_QueryString; } + [[nodiscard]] inline std::string_view BaseUri() const { return m_BaseUri; } // Service prefix struct QueryParams { @@ -120,7 +122,8 @@ protected: HttpContentType m_ContentType = HttpContentType::kBinary; HttpContentType m_AcceptType = HttpContentType::kUnknownContentType; uint64_t m_ContentLength = ~0ull; - std::string_view m_Uri; + std::string_view m_BaseUri; // Base URI path of the service handling this request + std::string_view m_Uri; // URI without service prefix std::string_view m_UriWithExtension; std::string_view m_QueryString; mutable uint32_t m_RequestId = ~uint32_t(0); diff --git a/src/zenhttp/servers/httpasio.cpp b/src/zenhttp/servers/httpasio.cpp index 12aee1ee0..4a0edfd29 100644 --- a/src/zenhttp/servers/httpasio.cpp +++ b/src/zenhttp/servers/httpasio.cpp @@ -1017,7 +1017,8 @@ private: ////////////////////////////////////////////////////////////////////////// HttpAsioServerRequest::HttpAsioServerRequest(HttpRequestParser& Request, HttpService& Service, IoBuffer PayloadBuffer) -: m_Request(Request) +: HttpServerRequest(Service) +, m_Request(Request) , m_PayloadBuffer(std::move(PayloadBuffer)) { const int PrefixLength = Service.UriPrefixLength(); diff --git a/src/zenhttp/servers/httpplugin.cpp b/src/zenhttp/servers/httpplugin.cpp index 426e62179..44a5b71d0 100644 --- a/src/zenhttp/servers/httpplugin.cpp +++ b/src/zenhttp/servers/httpplugin.cpp @@ -552,7 +552,8 @@ HttpPluginConnectionHandler::TerminateConnection() ////////////////////////////////////////////////////////////////////////// HttpPluginServerRequest::HttpPluginServerRequest(HttpRequestParser& Request, HttpService& Service, IoBuffer PayloadBuffer) -: m_Request(Request) +: HttpServerRequest(Service) +, m_Request(Request) , m_PayloadBuffer(std::move(PayloadBuffer)) { ZEN_MEMSCOPE(GetHttppluginTag()); diff --git a/src/zenhttp/servers/httpsys.cpp b/src/zenhttp/servers/httpsys.cpp index 7b02f95f1..87b66dcd1 100644 --- a/src/zenhttp/servers/httpsys.cpp +++ b/src/zenhttp/servers/httpsys.cpp @@ -15,6 +15,7 @@ #include <zencore/timer.h> #include <zencore/trace.h> #include <zenhttp/packageformat.h> +#include <zentelemetry/otlptrace.h> #include <EASTL/fixed_vector.h> @@ -36,6 +37,41 @@ GetHttpsysTag() return HttpsysTag; } +static void +GetAddressString(StringBuilderBase& OutString, const SOCKADDR* SockAddr, bool IncludePort = true) +{ + if (SockAddr) + { + // When a port is desired, use WSAAddressToStringA which includes the port. + if (IncludePort) + { + CHAR AddrBuf[64] = {}; + DWORD AddrBufLen = sizeof(AddrBuf); + const DWORD AddrLen = (SockAddr->sa_family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + + if (WSAAddressToStringA((LPSOCKADDR)SockAddr, AddrLen, nullptr, AddrBuf, &AddrBufLen) == 0) + { + OutString.Append(AddrBuf, AddrBufLen); + return; + } + } + else + { + // When port should be omitted, use getnameinfo with NI_NUMERICHOST to get only the numeric address. + CHAR HostBuf[64] = {}; + const int SockLen = (SockAddr->sa_family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + + if (getnameinfo((const SOCKADDR*)SockAddr, SockLen, HostBuf, (DWORD)sizeof(HostBuf), nullptr, 0, NI_NUMERICHOST) == 0) + { + OutString.Append(HostBuf, (DWORD)strlen(HostBuf)); + return; + } + } + } + + OutString.Append("unknown"); +} + /** * @brief Windows implementation of HTTP server based on http.sys * @@ -382,6 +418,8 @@ public: virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) override; void SuppressResponseBody(); // typically used for HEAD requests + inline int64_t GetResponseBodySize() const { return m_TotalDataSize; } + private: eastl::fixed_vector<HTTP_DATA_CHUNK, 16> m_HttpDataChunks; uint64_t m_TotalDataSize = 0; // Sum of all chunk sizes @@ -1605,6 +1643,27 @@ HttpSysTransaction::InvokeRequestHandler(HttpService& Service, IoBuffer Payload) // Default request handling +# if ZEN_WITH_OTEL + std::string_view Verb = ToString(ThisRequest.RequestVerb()); + std::string_view Uri = ThisRequest.m_UriUtf8.ToView(); + + ExtendableStringBuilder<64> SpanName; + SpanName << Verb << " " << Uri; + otel::ScopedSpan HttpSpan(SpanName.ToView(), [&](otel::Span& Span) { + Span.AddAttribute("http.request.method"sv, Verb); + Span.AddAttribute("url.path"sv, Uri); + // FIXME: should be total size including headers etc according to spec + Span.AddAttribute("http.request.size"sv, static_cast<int64_t>(ThisRequest.ContentLength())); + Span.SetKind(otel::Span::Kind::kServer); + + // client.address + const SOCKADDR* SockAddr = ThisRequest.m_HttpTx.HttpRequest()->Address.pRemoteAddress; + ExtendableStringBuilder<64> ClientAddr; + GetAddressString(ClientAddr, SockAddr, /* IncludePort */ false); + Span.AddAttribute("client.address"sv, ClientAddr.ToView()); + }); +# endif + if (!HandlePackageOffers(Service, ThisRequest, m_PackageHandler)) { Service.HandleRequest(ThisRequest); @@ -1616,7 +1675,8 @@ HttpSysTransaction::InvokeRequestHandler(HttpService& Service, IoBuffer Payload) ////////////////////////////////////////////////////////////////////////// HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& Service, IoBuffer PayloadBuffer) -: m_HttpTx(Tx) +: HttpServerRequest(Service) +, m_HttpTx(Tx) , m_PayloadBuffer(std::move(PayloadBuffer)) { const HTTP_REQUEST* HttpRequestPtr = Tx.HttpRequest(); @@ -1626,16 +1686,16 @@ HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& HttpContentType AcceptContentType = HttpContentType::kUnknownContentType; + WideToUtf8({(wchar_t*)HttpRequestPtr->CookedUrl.pAbsPath, gsl::narrow<size_t>(AbsPathLength)}, m_UriUtf8); + if (AbsPathLength >= PrefixLength) { // We convert the URI immediately because most of the code involved prefers to deal // with utf8. This is overhead which I'd prefer to avoid but for now we just have // to live with it - WideToUtf8({(wchar_t*)HttpRequestPtr->CookedUrl.pAbsPath + PrefixLength, gsl::narrow<size_t>(AbsPathLength - PrefixLength)}, - m_UriUtf8); - std::string_view UriSuffix8{m_UriUtf8}; + UriSuffix8.remove_prefix(PrefixLength); m_UriWithExtension = UriSuffix8; // Retain URI with extension for user access m_Uri = UriSuffix8; @@ -1662,7 +1722,6 @@ HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& } else { - m_UriUtf8.Reset(); m_Uri = {}; m_UriWithExtension = {}; } @@ -1771,6 +1830,14 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode) m_NextCompletionHandler = Response; +# if ZEN_WITH_OTEL + if (otel::Span* ActiveSpan = otel::Span::GetCurrentSpan()) + { + ActiveSpan->AddAttribute("http.response.body.size"sv, Response->GetResponseBodySize()); + ActiveSpan->AddAttribute("http.response.status_code"sv, static_cast<int64_t>(ResponseCode)); + } +# endif + SetIsHandled(); } @@ -1790,6 +1857,14 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentTy m_NextCompletionHandler = Response; +# if ZEN_WITH_OTEL + if (otel::Span* ActiveSpan = otel::Span::GetCurrentSpan()) + { + ActiveSpan->AddAttribute("http.response.body.size"sv, Response->GetResponseBodySize()); + ActiveSpan->AddAttribute("http.response.status_code"sv, static_cast<int64_t>(ResponseCode)); + } +# endif + SetIsHandled(); } @@ -1810,6 +1885,14 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentTy m_NextCompletionHandler = Response; +# if ZEN_WITH_OTEL + if (otel::Span* ActiveSpan = otel::Span::GetCurrentSpan()) + { + ActiveSpan->AddAttribute("http.response.body.size"sv, Response->GetResponseBodySize()); + ActiveSpan->AddAttribute("http.response.status_code"sv, static_cast<int64_t>(ResponseCode)); + } +# endif + SetIsHandled(); } diff --git a/src/zenserver-test/buildstore-tests.cpp b/src/zenserver-test/buildstore-tests.cpp index ec6f17d97..02b308485 100644 --- a/src/zenserver-test/buildstore-tests.cpp +++ b/src/zenserver-test/buildstore-tests.cpp @@ -353,7 +353,7 @@ TEST_CASE("buildstore.cache") { IoHash NoneBlob = IoHash::HashBuffer("data", 4); std::vector<BuildStorageCache::BlobExistsResult> NoneExists = Cache->BlobsExists(BuildId, std::vector<IoHash>{NoneBlob}); - CHECK(NoneExists.size() == 1); + REQUIRE(NoneExists.size() == 1); CHECK(!NoneExists[0].HasBody); CHECK(!NoneExists[0].HasMetadata); } diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp index 6bab33d92..34848c831 100644 --- a/src/zenserver/main.cpp +++ b/src/zenserver/main.cpp @@ -18,6 +18,7 @@ #include <zencore/string.h> #include <zencore/thread.h> #include <zencore/trace.h> +#include <zentelemetry/otlptrace.h> #include <zenutil/service.h> #include "diag/logging.h" @@ -102,6 +103,8 @@ AppMain(int argc, char* argv[]) #endif // ZEN_WITH_TRACE { + ZEN_OTEL_SPAN("AppMain::Configure"); + typename Main::Configurator Configurator(ServerOptions); Configurator.Configure(argc, argv); } diff --git a/src/zenserver/storage/zenstorageserver.cpp b/src/zenserver/storage/zenstorageserver.cpp index 827f22ecc..93a01d9d7 100644 --- a/src/zenserver/storage/zenstorageserver.cpp +++ b/src/zenserver/storage/zenstorageserver.cpp @@ -28,6 +28,7 @@ #include <zenstore/scrubcontext.h> #include <zenstore/vfsimpl.h> #include <zenstore/workspaces.h> +#include <zentelemetry/otlptrace.h> #include <zenutil/service.h> #include <zenutil/workerpools.h> #include <zenutil/zenserverprocess.h> @@ -185,6 +186,8 @@ ZenStorageServer::RegisterServices() void ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions) { + ZEN_OTEL_SPAN("InitializeServices"); + InitializeAuthentication(ServerOptions); ZEN_INFO("initializing storage"); @@ -206,6 +209,8 @@ ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions if (ServerOptions.WorksSpacesConfig.Enabled) { + ZEN_OTEL_SPAN("InitializeWorkspaces"); + m_Workspaces.reset(new Workspaces()); m_HttpWorkspacesService.reset( new HttpWorkspacesService(m_StatusService, @@ -239,6 +244,8 @@ ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions if (ServerOptions.ObjectStoreEnabled) { + ZEN_OTEL_SPAN("InitializeObjectStore"); + ObjectStoreConfig ObjCfg; ObjCfg.RootDirectory = m_DataRoot / "obj"; @@ -254,6 +261,8 @@ ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions if (ServerOptions.BuildStoreConfig.Enabled) { + ZEN_OTEL_SPAN("InitializeBuildStore"); + m_BuildStoreService = std::make_unique<HttpBuildStoreService>(m_StatusService, m_StatsService, *m_BuildStore); } @@ -347,6 +356,7 @@ ZenStorageServer::InitializeAuthentication(const ZenStorageServerConfig& ServerO void ZenStorageServer::InitializeState(const ZenStorageServerConfig& ServerOptions) { + ZEN_OTEL_SPAN("InitializeState"); ZEN_TRACE_CPU("ZenStorageServer::InitializeState"); // Check root manifest to deal with schema versioning @@ -451,6 +461,7 @@ ZenStorageServer::InitializeState(const ZenStorageServerConfig& ServerOptions) if (WipeState) { + ZEN_OTEL_SPAN("WipingState"); ZEN_WARN("Wiping state at '{}' - reason: '{}'", m_DataRoot, WipeReason); std::error_code Ec; @@ -517,6 +528,7 @@ ZenStorageServer::InitializeState(const ZenStorageServerConfig& ServerOptions) void ZenStorageServer::InitializeStructuredCache(const ZenStorageServerConfig& ServerOptions) { + ZEN_OTEL_SPAN("InitializeStructuredCache"); ZEN_TRACE_CPU("ZenStorageServer::InitializeStructuredCache"); using namespace std::literals; diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index e83624bbb..ab8dbb16b 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -23,6 +23,7 @@ #include <zencore/trace.h> #include <zencore/workthreadpool.h> #include <zenhttp/httpserver.h> +#include <zentelemetry/otlptrace.h> #include <zenutil/service.h> #include <zenutil/workerpools.h> #include <zenutil/zenserverprocess.h> @@ -77,6 +78,7 @@ ZenServerBase::~ZenServerBase() int ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry) { + ZEN_OTEL_SPAN("ZenServerBase::Initialize"); ZEN_TRACE_CPU("ZenServerBase::Initialize"); ZEN_MEMSCOPE(GetZenserverTag()); @@ -396,6 +398,8 @@ ZenServerMain::Run() if (m_ServerOptions.SentryConfig.Disable == false) { + ZEN_OTEL_SPAN("SentryInit"); + std::string SentryDatabasePath = (m_ServerOptions.DataDir / ".sentry-native").string(); std::string SentryAttachmentPath = m_ServerOptions.AbsLogFile.string(); diff --git a/src/zenstore/gc.cpp b/src/zenstore/gc.cpp index a4a141577..f5b1577c9 100644 --- a/src/zenstore/gc.cpp +++ b/src/zenstore/gc.cpp @@ -19,6 +19,7 @@ #include <zencore/workthreadpool.h> #include <zenstore/cidstore.h> #include <zenstore/scrubcontext.h> +#include <zentelemetry/otlptrace.h> #include <zenutil/workerpools.h> #include "cas.h" @@ -2746,6 +2747,8 @@ GcScheduler::CollectGarbage(const GcClock::TimePoint& CacheExpireTime, const auto _ = MakeGuard([&] { ReclaimDiskReserve(); }); { + zen::otel::ScopedSpan GcSpan("CollectGarbage"); + Stopwatch Timer; const auto __ = MakeGuard([&] { ZEN_INFO("garbage collection DONE in {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs())); }); @@ -2753,8 +2756,9 @@ GcScheduler::CollectGarbage(const GcClock::TimePoint& CacheExpireTime, switch (UseGCVersion) { case GcVersion::kV1_Deprecated: - ZEN_WARN("GCV1: Depreated - no GC will be executed"); + ZEN_WARN("GCV1: Deprecated - no GC will be executed"); break; + case GcVersion::kV2: { std::string GcId = Oid::NewOid().ToString(); diff --git a/src/zenstore/xmake.lua b/src/zenstore/xmake.lua index 31289a573..ea8155e94 100644 --- a/src/zenstore/xmake.lua +++ b/src/zenstore/xmake.lua @@ -6,6 +6,6 @@ target('zenstore') add_headerfiles("**.h") add_files("**.cpp") add_includedirs("include", {public=true}) - add_deps("zencore", "zenutil", "zenvfs") + add_deps("zencore", "zentelemetry", "zenutil", "zenvfs") add_deps("robin-map") add_packages("eastl", {public=true}); diff --git a/src/zentelemetry/include/zentelemetry/otlptrace.h b/src/zentelemetry/include/zentelemetry/otlptrace.h index ebecff91a..f191241ed 100644 --- a/src/zentelemetry/include/zentelemetry/otlptrace.h +++ b/src/zentelemetry/include/zentelemetry/otlptrace.h @@ -3,6 +3,7 @@ #pragma once #include <zenbase/refcount.h> +#include <zencore/memcmp.h> #include <zencore/uid.h> #include <span> @@ -30,8 +31,6 @@ using AttributeList = std::span<std::pair<std::string, std::string>>; class Tracer; -Tracer& GetTracer(); - // OLTP Span ID struct SpanId @@ -42,8 +41,16 @@ struct SpanId explicit SpanId(const std::span<const uint8_t, 8> Bytes) noexcept { std::copy(Bytes.begin(), Bytes.end(), Id); } explicit SpanId(const Oid& InId) noexcept { memcpy(Id, reinterpret_cast<const uint8_t*>(InId.OidBits), sizeof Id); } - auto operator<=>(const SpanId& Rhs) const = default; - inline operator bool() const { return *this != SpanId(); } + std::strong_ordering operator<=>(const SpanId& Rhs) const noexcept + { + int cmp = MemCmpFixed<kSize>(Id, Rhs.Id); + if (cmp < 0) + return std::strong_ordering::less; + if (cmp > 0) + return std::strong_ordering::greater; + return std::strong_ordering::equal; + } + inline operator bool() const { return *reinterpret_cast<const uint64_t*>(Id) != 0; } static SpanId NewSpanId(); @@ -64,8 +71,19 @@ struct TraceId inline TraceId() noexcept : Id{0} {} explicit TraceId(const std::span<const uint8_t, kSize> Bytes) noexcept { std::copy(Bytes.begin(), Bytes.end(), Id); } - auto operator<=>(const TraceId& Rhs) const = default; - inline operator bool() const { return *this != TraceId(); } + std::strong_ordering operator<=>(const TraceId& Rhs) const noexcept + { + int cmp = MemCmpFixed<kSize>(Id, Rhs.Id); + if (cmp < 0) + return std::strong_ordering::less; + if (cmp > 0) + return std::strong_ordering::greater; + return std::strong_ordering::equal; + } + inline operator bool() const + { + return !(reinterpret_cast<const uint64_t*>(Id)[0] == 0 && reinterpret_cast<const uint64_t*>(Id)[1] == 0); + } static TraceId NewTraceId(); @@ -194,7 +212,6 @@ private: uint64_t m_StartTime = 0; uint64_t m_EndTime = 0; Kind m_Kind = Kind::kInternal; - bool m_Ended = false; Span(MemoryArena& Arena, std::string_view Name, Span* SpanChain); ~Span(); @@ -209,6 +226,13 @@ class ScopedSpan final { public: ScopedSpan(std::string_view Name); + ScopedSpan(std::string_view Name, std::invocable<Span&> auto&& InitializerFunction) : ScopedSpan(Name) + { + if (m_Span) + { + InitializerFunction(*m_Span); + } + } ScopedSpan() = delete; ~ScopedSpan(); @@ -217,7 +241,8 @@ public: ScopedSpan(ScopedSpan&& Rhs) = default; ScopedSpan(const ScopedSpan& Rhs) = default; - Span* operator->() const { return m_Span.Get(); } + operator bool() const { return !!m_Span; } + void WithSpan(auto Func) const { Func(*m_Span); } private: ScopedSpan(Span* InSpan, Tracer* InTracer); diff --git a/src/zentelemetry/otlptrace.cpp b/src/zentelemetry/otlptrace.cpp index b634eacf6..f987afcfe 100644 --- a/src/zentelemetry/otlptrace.cpp +++ b/src/zentelemetry/otlptrace.cpp @@ -7,6 +7,7 @@ # include <zencore/endian.h> # include <zencore/memory/memoryarena.h> +# include <zencore/scopeguard.h> # include <zencore/session.h> # include <zencore/testing.h> # include <zencore/uid.h> @@ -106,16 +107,15 @@ Span::~Span() void Span::End() { - if (m_Ended) + if (m_EndTime) { return; } - ZEN_ASSERT(t_TraceState.ActiveSpan == this); + ZEN_ASSERT_SLOW(t_TraceState.ActiveSpan == this); - m_Ended = true; - t_TraceState.ActiveSpan = m_ParentSpan; m_EndTime = NowInNanoseconds(); + t_TraceState.ActiveSpan = m_ParentSpan; } Span* @@ -127,10 +127,10 @@ Span::GetCurrentSpan() SpanId Span::GetCurrentSpanId(TraceId& OutTraceId) { - if (t_TraceState.ActiveSpan) + if (const auto& State = t_TraceState; State.ActiveSpan) { - OutTraceId = t_TraceState.CurrentTraceId; - return t_TraceState.ActiveSpan->m_SpanId; + OutTraceId = State.CurrentTraceId; + return State.ActiveSpan->m_SpanId; } else { @@ -271,6 +271,14 @@ IsRecording() ////////////////////////////////////////////////////////////////////////// +std::atomic<bool> g_OtlpTraceEnabled{false}; + +inline bool +IsOtlpTraceEnabled() +{ + return g_OtlpTraceEnabled.load(); +} + thread_local Tracer* t_Tracer; struct Tracer::Impl @@ -325,22 +333,19 @@ Tracer::GetTracer() ScopedSpan Tracer::CreateSpan(std::string_view Name) { - Tracer* TracerPtr = GetTracer(); - - Impl* const ImplPtr = TracerPtr->m_Impl; - - Span* NewSpan = new (ImplPtr->m_Arena) Span(ImplPtr->m_Arena, Name, ImplPtr->m_SpanChain); - - ImplPtr->m_SpanChain = NewSpan; - ImplPtr->m_SpanCount.fetch_add(1); - - return ScopedSpan(NewSpan, TracerPtr); + return ScopedSpan(Name); } ////////////////////////////////////////////////////////////////////////// ScopedSpan::ScopedSpan(std::string_view Name) { + if (!IsOtlpTraceEnabled()) + { + // m_Tracer and m_Span remain null + return; + } + Tracer* TracerPtr = Tracer::GetTracer(); Tracer::Impl* const ImplPtr = TracerPtr->m_Impl; @@ -379,15 +384,24 @@ otlptrace_forcelink() TEST_CASE("otlp.trace") { + // Enable OTLP tracing for the duration of this test + auto _ = MakeGuard([PreviousState = zen::otel::g_OtlpTraceEnabled.load()]() { zen::otel::g_OtlpTraceEnabled.store(PreviousState); }); + zen::otel::g_OtlpTraceEnabled.store(true); + { - ScopedSpan Span = Tracer::CreateSpan("span0"); - Span->AddEvent("TestEvent1"sv); - Span->AddEvent("TestEvent2"sv); + ScopedSpan Span0("span0", [](Span& S) { + S.AddAttribute("attr1"sv, "value1"sv); + S.AddAttribute("attr2"sv, 42ULL); + S.AddEvent("TestEvent1"sv); + S.AddEvent("TestEvent2"sv); + }); { - ScopedSpan Span2 = Tracer::CreateSpan("span1"); - Span2->AddEvent("TestEvent3"sv); - Span2->AddEvent("TestEvent4"sv); + ScopedSpan Span1 = Tracer::CreateSpan("span1"); + Span1.WithSpan([](Span& S) { + S.AddEvent("TestEvent3"sv); + S.AddEvent("TestEvent4"sv); + }); } } } |