diff options
| author | Stefan Boberg <[email protected]> | 2025-12-11 16:12:02 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2025-12-11 16:12:02 +0100 |
| commit | 567293ab1baa8cb0eca843977c520e5b8f400b4d (patch) | |
| tree | 1f54f12d3fb19b91695bbfea33fa9abd8de49f69 /src/zenhttp/servers/httpsys.cpp | |
| parent | 5.7.14 (diff) | |
| download | zen-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.cpp | 93 |
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(); } |