diff options
Diffstat (limited to 'src/zenhttp/monitoring/httpstats.cpp')
| -rw-r--r-- | src/zenhttp/monitoring/httpstats.cpp | 186 |
1 files changed, 115 insertions, 71 deletions
diff --git a/src/zenhttp/monitoring/httpstats.cpp b/src/zenhttp/monitoring/httpstats.cpp index 3877215a8..5ad5ebcc7 100644 --- a/src/zenhttp/monitoring/httpstats.cpp +++ b/src/zenhttp/monitoring/httpstats.cpp @@ -16,6 +16,7 @@ HttpStatsService::HttpStatsService(bool EnableWebSockets) : m_Log(logging::Get(" m_PushEnabled.store(true); m_PushThread = std::thread([this] { PushThreadFunction(); }); } + Initialize(); } HttpStatsService::HttpStatsService(asio::io_context& IoContext, bool EnableWebSockets) : m_Log(logging::Get("stats")) @@ -26,6 +27,110 @@ HttpStatsService::HttpStatsService(asio::io_context& IoContext, bool EnableWebSo m_PushTimer = std::make_unique<asio::steady_timer>(IoContext); EnqueuePushTimer(); } + Initialize(); +} + +void +HttpStatsService::Initialize() +{ + m_Router.AddMatcher("handler_id", [](std::string_view Str) -> bool { + if (Str.empty()) + { + return false; + } + for (const auto C : Str) + { + if (std::isalnum(C) || C == '$') + { + // fine + } + else + { + // not fine + return false; + } + } + return true; + }); + + m_Router.RegisterRoute( + "activity_counters", + [this](HttpRouterRequest& Request) { + CbObjectWriter Obj; + + std::uint64_t SumActivity = 0; + + std::vector<std::pair<std::string, uint64_t>> Activities; + { + RwLock::SharedLockScope _(m_Lock); + Activities.reserve(m_Providers.size()); + for (const auto& It : m_Providers) + { + const std::string& HandlerName = It.first; + IHttpStatsProvider* Provider = It.second; + ZEN_ASSERT(Provider != nullptr); + uint64_t ProviderActivityCounter = Provider->GetActivityCounter(); + if (ProviderActivityCounter != 0) + { + Activities.push_back(std::make_pair(HandlerName, ProviderActivityCounter)); + } + SumActivity += ProviderActivityCounter; + } + } + + Obj.BeginArray("providers"); + for (const std::pair<std::string, uint64_t>& Activity : Activities) + { + const std::string& HandlerName = Activity.first; + uint64_t ProviderActivityCounter = Activity.second; + Obj.BeginObject(); + { + Obj.AddString("provider", HandlerName); + Obj.AddInteger("activity_counter", ProviderActivityCounter); + } + Obj.EndObject(); + } + Obj.EndArray(); + + Obj.AddInteger("sum", SumActivity); + + Request.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "{handler_id}", + [this](HttpRouterRequest& Request) { + std::string_view Handler = Request.GetCapture(1); + RwLock::SharedLockScope _(m_Lock); + if (auto It = m_Providers.find(std::string{Handler}); It != end(m_Providers)) + { + return It->second->HandleStatsRequest(Request.ServerRequest()); + } + Request.ServerRequest().WriteResponse(HttpResponseCode::NotFound); + }, + HttpVerb::kHead | HttpVerb::kGet); + + m_Router.RegisterRoute( + "", + [this](HttpRouterRequest& Request) { + CbObjectWriter Cbo; + + Cbo.BeginArray("providers"); + + { + RwLock::SharedLockScope _(m_Lock); + for (auto& Kv : m_Providers) + { + Cbo << Kv.first; + } + } + + Cbo.EndArray(); + + Request.ServerRequest().WriteResponse(HttpResponseCode::OK, Cbo.Save()); + }, + HttpVerb::kHead | HttpVerb::kGet); } HttpStatsService::~HttpStatsService() @@ -82,54 +187,7 @@ void HttpStatsService::HandleRequest(HttpServerRequest& Request) { ZEN_TRACE_CPU("HttpStatsService::HandleRequest"); - using namespace std::literals; - - std::string_view Key = Request.RelativeUri(); - - switch (Request.RequestVerb()) - { - case HttpVerb::kHead: - case HttpVerb::kGet: - { - if (Key.empty()) - { - CbObjectWriter Cbo; - - Cbo.BeginArray("providers"); - - { - RwLock::SharedLockScope _(m_Lock); - for (auto& Kv : m_Providers) - { - Cbo << Kv.first; - } - } - - Cbo.EndArray(); - - Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); - } - else if (Key[0] == '/') - { - Key.remove_prefix(1); - size_t SlashPos = Key.find_first_of("/?"); - if (SlashPos != std::string::npos) - { - Key = Key.substr(0, SlashPos); - } - - RwLock::SharedLockScope _(m_Lock); - if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) - { - return It->second->HandleStatsRequest(Request); - } - } - } - - [[fallthrough]]; - default: - return; - } + m_Router.HandleRequest(Request); } ////////////////////////////////////////////////////////////////////////// @@ -138,8 +196,9 @@ HttpStatsService::HandleRequest(HttpServerRequest& Request) // void -HttpStatsService::OnWebSocketOpen(Ref<WebSocketConnection> Connection) +HttpStatsService::OnWebSocketOpen(Ref<WebSocketConnection> Connection, std::string_view RelativeUri) { + ZEN_UNUSED(RelativeUri); ZEN_TRACE_CPU("HttpStatsService::OnWebSocketOpen"); ZEN_INFO("Stats WebSocket client connected"); @@ -189,11 +248,8 @@ HttpStatsService::BroadcastStats() return; } - // Collect stats from all providers - ExtendableStringBuilder<4096> JsonBuilder; - JsonBuilder.Append("{"); - - bool First = true; + // Collect stats from all providers into a single CBO object, then convert to JSON + CbObjectWriter Writer; { RwLock::SharedLockScope _(m_Lock); for (auto& [Id, Provider] : m_Providers) @@ -203,27 +259,15 @@ HttpStatsService::BroadcastStats() { continue; } - - if (!First) - { - JsonBuilder.Append(","); - } - First = false; - - // Emit as "provider_id": { ... } - JsonBuilder.Append("\""); - JsonBuilder.Append(Id); - JsonBuilder.Append("\":"); - - ExtendableStringBuilder<2048> StatsJson; - Stats.ToJson(StatsJson); - JsonBuilder.Append(StatsJson.ToView()); + Writer.AddObject(Id, Stats); } } - JsonBuilder.Append("}"); - + CbObject Payload = Writer.Save(); + ExtendableStringBuilder<4096> JsonBuilder; + Payload.ToJson(JsonBuilder); std::string_view Json = JsonBuilder.ToView(); + for (auto& Conn : Connections) { if (Conn->IsOpen()) |