aboutsummaryrefslogtreecommitdiff
path: root/zenserver
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2021-11-18 18:50:09 +0100
committerPer Larsson <[email protected]>2021-11-18 18:50:09 +0100
commit78ef39fdfa3c7ccf6531c3ff77baf2ca7e8a42ff (patch)
tree8b0419f93d8a0b6002dd856222ffd998d51f71c4 /zenserver
parentChange error code for failed upsteam apply (diff)
downloadzen-78ef39fdfa3c7ccf6531c3ff77baf2ca7e8a42ff.tar.xz
zen-78ef39fdfa3c7ccf6531c3ff77baf2ca7e8a42ff.zip
Extended Health endpoint with support for returning build version and log file.
Diffstat (limited to 'zenserver')
-rw-r--r--zenserver/diag/diagsvcs.cpp113
-rw-r--r--zenserver/diag/diagsvcs.h28
-rw-r--r--zenserver/zenserver.cpp20
-rw-r--r--zenserver/zenserver.vcxproj1
-rw-r--r--zenserver/zenserver.vcxproj.filters3
5 files changed, 144 insertions, 21 deletions
diff --git a/zenserver/diag/diagsvcs.cpp b/zenserver/diag/diagsvcs.cpp
new file mode 100644
index 000000000..edd9b782e
--- /dev/null
+++ b/zenserver/diag/diagsvcs.cpp
@@ -0,0 +1,113 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "diagsvcs.h"
+
+#include <zencore/compactbinary.h>
+#include <zencore/compactbinarybuilder.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;
+
+bool
+ReadFile(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(
+ "",
+ [this](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;
+ 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;
+
+ ExtendableStringBuilder<256> Sb;
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kJSON, Writer.Save().ToJson(Sb).ToView());
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "log",
+ [this](HttpRouterRequest& RoutedReq) {
+ HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
+
+ zen::Log().flush();
+
+ std::filesystem::path Path =
+ m_HealthInfo.AbsLogPath.empty() ? m_HealthInfo.DataRoot / "logs/zenserver.log" : m_HealthInfo.AbsLogPath;
+
+ ExtendableStringBuilder<4096> Sb;
+ if (ReadFile(Path.string(), Sb) && Sb.Size() > 0)
+ {
+ HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Sb.ToView());
+ }
+ else
+ {
+ HttpReq.WriteResponse(HttpResponseCode::NotFound);
+ }
+ },
+ HttpVerb::kGet);
+}
+
+void
+HttpHealthService::SetHealthInfo(HealthServiceInfo&& Info)
+{
+ 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/zenserver/diag/diagsvcs.h b/zenserver/diag/diagsvcs.h
index 61703e393..bd03f8023 100644
--- a/zenserver/diag/diagsvcs.h
+++ b/zenserver/diag/diagsvcs.h
@@ -5,6 +5,8 @@
#include <zencore/iobuffer.h>
#include <zenhttp/httpserver.h>
+#include <filesystem>
+
//////////////////////////////////////////////////////////////////////////
namespace zen {
@@ -82,26 +84,28 @@ private:
IoBuffer m_1k{m_1m, 0u, 1024};
};
+struct HealthServiceInfo
+{
+ std::filesystem::path DataRoot;
+ std::filesystem::path AbsLogPath;
+ std::string HttpServerClass;
+ std::string BuildVersion;
+};
+
class HttpHealthService : public HttpService
{
public:
- HttpHealthService() = default;
+ HttpHealthService();
~HttpHealthService() = default;
- virtual const char* BaseUri() const override { return "/health/"; }
+ void SetHealthInfo(HealthServiceInfo&& Info);
- virtual void HandleRequest(HttpServerRequest& Request) override
- {
- using namespace std::literals;
-
- switch (Request.RequestVerb())
- {
- case HttpVerb::kGet:
- return Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv);
- }
- }
+ virtual const char* BaseUri() const override;
+ virtual void HandleRequest(HttpServerRequest& Request) override final;
private:
+ HttpRequestRouter m_Router;
+ HealthServiceInfo m_HealthInfo;
};
} // namespace zen
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index a330fb558..b36d84c22 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -151,16 +151,13 @@ namespace utils {
class ZenServer : public IHttpStatusProvider
{
public:
- void Initialize(ZenServiceConfig& ServiceConfig,
- std::string_view HttpServerClass,
- int BasePort,
- int ParentPid,
- ZenServerState::ZenServerEntry* ServerEntry)
+ void Initialize(ZenServiceConfig& ServiceConfig, const ZenServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry)
{
using namespace fmt::literals;
m_ServerEntry = ServerEntry;
m_DebugOptionForcedCrash = ServiceConfig.ShouldCrash;
+ const int ParentPid = ServerOptions.OwnerPid;
if (ParentPid)
{
@@ -184,7 +181,7 @@ public:
// Initialize/check mutex based on base port
- std::string MutexName = "zen_{}"_format(BasePort);
+ std::string MutexName = "zen_{}"_format(ServerOptions.BasePort);
if (zen::NamedMutex::Exists(MutexName) || ((m_ServerMutex.Create(MutexName) == false)))
{
@@ -193,10 +190,15 @@ public:
InitializeState(ServiceConfig);
+ m_HealthService.SetHealthInfo({.DataRoot = m_DataRoot,
+ .AbsLogPath = ServerOptions.AbsLogFile,
+ .HttpServerClass = std::string(ServerOptions.HttpServerClass),
+ .BuildVersion = std::string(BUILD_VERSION)});
+
// Ok so now we're configured, let's kick things off
- m_Http = zen::CreateHttpServer(HttpServerClass);
- m_Http->Initialize(BasePort);
+ m_Http = zen::CreateHttpServer(ServerOptions.HttpServerClass);
+ m_Http->Initialize(ServerOptions.BasePort);
m_Http->RegisterService(m_HealthService);
m_Http->RegisterService(m_StatsService);
m_Http->RegisterService(m_StatusService);
@@ -855,7 +857,7 @@ ZenWindowsService::Run()
Server.SetContentRoot(GlobalOptions.ContentDir);
Server.SetTestMode(GlobalOptions.IsTest);
Server.SetDedicatedMode(GlobalOptions.IsDedicated);
- Server.Initialize(ServiceConfig, GlobalOptions.HttpServerClass, GlobalOptions.BasePort, GlobalOptions.OwnerPid, Entry);
+ Server.Initialize(ServiceConfig, GlobalOptions, Entry);
// Monitor shutdown signals
diff --git a/zenserver/zenserver.vcxproj b/zenserver/zenserver.vcxproj
index 480d5dd15..935979cc3 100644
--- a/zenserver/zenserver.vcxproj
+++ b/zenserver/zenserver.vcxproj
@@ -136,6 +136,7 @@
<ClCompile Include="cache\structuredcachestore.cpp" />
<ClCompile Include="compute\apply.cpp" />
<ClCompile Include="config.cpp" />
+ <ClCompile Include="diag\diagsvcs.cpp" />
<ClCompile Include="diag\logging.cpp" />
<ClCompile Include="experimental\frontend.cpp" />
<ClCompile Include="experimental\vfs.cpp" />
diff --git a/zenserver/zenserver.vcxproj.filters b/zenserver/zenserver.vcxproj.filters
index 6de9230d3..a6e57d8b7 100644
--- a/zenserver/zenserver.vcxproj.filters
+++ b/zenserver/zenserver.vcxproj.filters
@@ -82,6 +82,9 @@
<ClCompile Include="upstream\upstreamapply.cpp">
<Filter>upstream</Filter>
</ClCompile>
+ <ClCompile Include="diag\diagsvcs.cpp">
+ <Filter>diag</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="cache">