aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-10-13 09:55:27 +0200
committerGitHub <[email protected]>2023-10-13 09:55:27 +0200
commit74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d (patch)
treeacae59dac67b4d051403f35e580201c214ec4fda /src/zenserver
parentfaster oplog iteration (#471) (diff)
downloadzen-74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d.tar.xz
zen-74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d.zip
restructured zenhttp (#472)
separating the http server implementations into a directory and moved diagsvcs into zenserver since it's somewhat hard-coded for it
Diffstat (limited to 'src/zenserver')
-rw-r--r--src/zenserver/diag/diagsvcs.cpp135
-rw-r--r--src/zenserver/diag/diagsvcs.h119
-rw-r--r--src/zenserver/zenserver.h2
3 files changed, 255 insertions, 1 deletions
diff --git a/src/zenserver/diag/diagsvcs.cpp b/src/zenserver/diag/diagsvcs.cpp
new file mode 100644
index 000000000..93c2eafc3
--- /dev/null
+++ b/src/zenserver/diag/diagsvcs.cpp
@@ -0,0 +1,135 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "diagsvcs.h"
+
+#include <zencore/compactbinary.h>
+#include <zencore/compactbinarybuilder.h>
+#include <zencore/config.h>
+#include <zencore/filesystem.h>
+#include <zencore/logging.h>
+#include <zencore/string.h>
+#include <fstream>
+#include <sstream>
+
+#include <json11.hpp>
+
+namespace zen {
+
+using namespace std::literals;
+
+static bool
+ReadLogFile(const std::string& Path, StringBuilderBase& Out)
+{
+ try
+ {
+ constexpr auto ReadSize = std::size_t{4096};
+ auto FileStream = std::ifstream{Path};
+
+ std::string Buf(ReadSize, '\0');
+ while (FileStream.read(&Buf[0], ReadSize))
+ {
+ Out.Append(std::string_view(&Buf[0], FileStream.gcount()));
+ }
+ Out.Append(std::string_view(&Buf[0], FileStream.gcount()));
+
+ return true;
+ }
+ catch (std::exception&)
+ {
+ Out.Reset();
+ return false;
+ }
+}
+
+HttpHealthService::HttpHealthService()
+{
+ m_Router.RegisterRoute(
+ "",
+ [](HttpRouterRequest& RoutedReq) {
+ HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv);
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "info",
+ [this](HttpRouterRequest& RoutedReq) {
+ HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
+
+ CbObjectWriter Writer;
+
+ {
+ RwLock::SharedLockScope _(m_InfoLock);
+ Writer << "DataRoot"sv << m_HealthInfo.DataRoot.string();
+ Writer << "AbsLogPath"sv << m_HealthInfo.AbsLogPath.string();
+ Writer << "BuildVersion"sv << m_HealthInfo.BuildVersion;
+ Writer << "HttpServerClass"sv << m_HealthInfo.HttpServerClass;
+ }
+
+ HttpReq.WriteResponse(HttpResponseCode::OK, Writer.Save());
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "log",
+ [this](HttpRouterRequest& RoutedReq) {
+ HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
+
+ zen::Log().flush();
+
+ std::filesystem::path Path = [&] {
+ RwLock::SharedLockScope _(m_InfoLock);
+ return m_HealthInfo.AbsLogPath.empty() ? m_HealthInfo.DataRoot / "logs/zenserver.log" : m_HealthInfo.AbsLogPath;
+ }();
+
+ ExtendableStringBuilder<4096> Sb;
+ if (ReadLogFile(Path.string(), Sb) && Sb.Size() > 0)
+ {
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Sb.ToView());
+ }
+ else
+ {
+ HttpReq.WriteResponse(HttpResponseCode::NotFound);
+ }
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "version",
+ [this](HttpRouterRequest& RoutedReq) {
+ HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
+ if (HttpReq.GetQueryParams().GetValue("detailed") == "true")
+ {
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, ZEN_CFG_VERSION_BUILD_STRING_FULL);
+ }
+ else
+ {
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, ZEN_CFG_VERSION);
+ }
+ },
+ HttpVerb::kGet);
+}
+
+void
+HttpHealthService::SetHealthInfo(HealthServiceInfo&& Info)
+{
+ RwLock::ExclusiveLockScope _(m_InfoLock);
+ m_HealthInfo = std::move(Info);
+}
+
+const char*
+HttpHealthService::BaseUri() const
+{
+ return "/health/";
+}
+
+void
+HttpHealthService::HandleRequest(HttpServerRequest& Request)
+{
+ if (!m_Router.HandleRequest(Request))
+ {
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv);
+ }
+}
+
+} // namespace zen
diff --git a/src/zenserver/diag/diagsvcs.h b/src/zenserver/diag/diagsvcs.h
new file mode 100644
index 000000000..8cc869c83
--- /dev/null
+++ b/src/zenserver/diag/diagsvcs.h
@@ -0,0 +1,119 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include <zencore/iobuffer.h>
+#include <zenhttp/httpserver.h>
+
+#include <filesystem>
+
+//////////////////////////////////////////////////////////////////////////
+
+namespace zen {
+
+/** HTTP test endpoint
+
+ This is intended to be used to exercise basic HTTP communication infrastructure
+ which is useful for benchmarking performance of the server code and when evaluating
+ network performance / diagnosing connectivity issues
+
+ */
+class HttpTestService : public HttpService
+{
+public:
+ HttpTestService() {}
+ ~HttpTestService() = default;
+
+ virtual const char* BaseUri() const override { return "/test/"; }
+
+ virtual void HandleRequest(HttpServerRequest& Request) override
+ {
+ using namespace std::literals;
+
+ auto Uri = Request.RelativeUri();
+
+ if (Uri == "hello"sv)
+ {
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"hello world!"sv);
+ }
+ else if (Uri == "1K"sv)
+ {
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1k);
+ }
+ else if (Uri == "1M"sv)
+ {
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1m);
+ }
+ else if (Uri == "1M_1k"sv)
+ {
+ std::vector<IoBuffer> Buffers;
+ Buffers.reserve(1024);
+
+ for (int i = 0; i < 1024; ++i)
+ {
+ Buffers.push_back(m_1k);
+ }
+
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers);
+ }
+ else if (Uri == "1G"sv)
+ {
+ std::vector<IoBuffer> Buffers;
+ Buffers.reserve(1024);
+
+ for (int i = 0; i < 1024; ++i)
+ {
+ Buffers.push_back(m_1m);
+ }
+
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers);
+ }
+ else if (Uri == "1G_1k"sv)
+ {
+ std::vector<IoBuffer> Buffers;
+ Buffers.reserve(1024 * 1024);
+
+ for (int i = 0; i < 1024 * 1024; ++i)
+ {
+ Buffers.push_back(m_1k);
+ }
+
+ Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers);
+ }
+ }
+
+private:
+ IoBuffer m_1m{1024 * 1024};
+ IoBuffer m_1k{m_1m, 0u, 1024};
+};
+
+struct HealthServiceInfo
+{
+ std::filesystem::path DataRoot;
+ std::filesystem::path AbsLogPath;
+ std::string HttpServerClass;
+ std::string BuildVersion;
+};
+
+/** Health monitoring endpoint
+
+ Thji
+ */
+class HttpHealthService : public HttpService
+{
+public:
+ HttpHealthService();
+ ~HttpHealthService() = default;
+
+ void SetHealthInfo(HealthServiceInfo&& Info);
+
+ virtual const char* BaseUri() const override;
+ virtual void HandleRequest(HttpServerRequest& Request) override final;
+
+private:
+ HttpRequestRouter m_Router;
+ RwLock m_InfoLock;
+ HealthServiceInfo m_HealthInfo;
+};
+
+} // namespace zen
diff --git a/src/zenserver/zenserver.h b/src/zenserver/zenserver.h
index 0c28c1229..cc5b53cef 100644
--- a/src/zenserver/zenserver.h
+++ b/src/zenserver/zenserver.h
@@ -21,7 +21,6 @@ ZEN_THIRD_PARTY_INCLUDES_END
#include <zenhttp/auth/authmgr.h>
#include <zenhttp/auth/authservice.h>
-#include <zenhttp/diagsvcs.h>
#include <zenhttp/httpstats.h>
#include <zenhttp/httpstatus.h>
#include <zenhttp/httptest.h>
@@ -29,6 +28,7 @@ ZEN_THIRD_PARTY_INCLUDES_END
#include "admin/admin.h"
#include "cache/httpstructuredcache.h"
#include "cache/structuredcachestore.h"
+#include "diag/diagsvcs.h"
#include "frontend/frontend.h"
#include "httpcidstore.h"
#include "objectstore/objectstore.h"