aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/zenhttp/httpserver.cpp56
-rw-r--r--src/zenhttp/include/zenhttp/httpserver.h7
-rw-r--r--src/zenhttp/servers/httpasio.cpp3
-rw-r--r--src/zenhttp/servers/httpplugin.cpp3
-rw-r--r--src/zenhttp/servers/httpsys.cpp93
-rw-r--r--src/zenserver-test/buildstore-tests.cpp2
-rw-r--r--src/zenserver/main.cpp3
-rw-r--r--src/zenserver/storage/zenstorageserver.cpp12
-rw-r--r--src/zenserver/zenserver.cpp4
-rw-r--r--src/zenstore/gc.cpp6
-rw-r--r--src/zenstore/xmake.lua2
-rw-r--r--src/zentelemetry/include/zentelemetry/otlptrace.h41
-rw-r--r--src/zentelemetry/otlptrace.cpp60
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);
+ });
}
}
}