aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/httpsys.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-12-11 16:12:02 +0100
committerGitHub Enterprise <[email protected]>2025-12-11 16:12:02 +0100
commit567293ab1baa8cb0eca843977c520e5b8f400b4d (patch)
tree1f54f12d3fb19b91695bbfea33fa9abd8de49f69 /src/zenhttp/servers/httpsys.cpp
parent5.7.14 (diff)
downloadzen-567293ab1baa8cb0eca843977c520e5b8f400b4d.tar.xz
zen-567293ab1baa8cb0eca843977c520e5b8f400b4d.zip
add otel instrumentation (#581)
this change adds OTEL tracing to a few places * Top-level application lifecycle (config/init/cleanup, main loop) * http.sys requests it also brings some otlptrace optimizations and dynamic configuration of tracing. OTLP tracing is currently always disabled
Diffstat (limited to 'src/zenhttp/servers/httpsys.cpp')
-rw-r--r--src/zenhttp/servers/httpsys.cpp93
1 files changed, 88 insertions, 5 deletions
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();
}