diff options
| author | Stefan Boberg <[email protected]> | 2025-10-14 11:32:16 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2025-10-14 11:32:16 +0200 |
| commit | ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2 (patch) | |
| tree | 005a50adfddf6982bab3a06bb93d4c50da1a11fd /src/zenserver/admin/admin.cpp | |
| parent | make asiohttp work without IPv6 (#562) (diff) | |
| download | zen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.tar.xz zen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.zip | |
move all storage-related services into storage tree (#571)
* move all storage-related services into storage tree
* move config into config/
* also move admin service into storage since it mostly has storage related functionality
* header consolidation
Diffstat (limited to 'src/zenserver/admin/admin.cpp')
| -rw-r--r-- | src/zenserver/admin/admin.cpp | 805 |
1 files changed, 0 insertions, 805 deletions
diff --git a/src/zenserver/admin/admin.cpp b/src/zenserver/admin/admin.cpp deleted file mode 100644 index 97522e892..000000000 --- a/src/zenserver/admin/admin.cpp +++ /dev/null @@ -1,805 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "admin.h" - -#include <zencore/compactbinarybuilder.h> -#include <zencore/filesystem.h> -#include <zencore/fmtutils.h> -#include <zencore/jobqueue.h> -#include <zencore/logging.h> -#include <zencore/string.h> - -#if ZEN_WITH_TRACE -# include <zencore/trace.h> -#endif // ZEN_WITH_TRACE - -#if ZEN_USE_MIMALLOC -# include <mimalloc.h> -#endif - -#include <zenstore/gc.h> - -#include <zenstore/cache/structuredcachestore.h> -#include <zenutil/workerpools.h> -#include "config.h" - -#include <chrono> - -namespace zen { - -struct DirStats -{ - uint64_t FileCount = 0; - uint64_t DirCount = 0; - uint64_t ByteCount = 0; -}; - -DirStats -GetStatsForDirectory(std::filesystem::path Dir) -{ - if (!IsDir(Dir)) - return {}; - - struct StatsTraversal : public GetDirectoryContentVisitor - { - virtual void AsyncVisitDirectory(const std::filesystem::path& RelativeRoot, DirectoryContent&& Content) override - { - ZEN_UNUSED(RelativeRoot); - - uint64_t FileCount = Content.FileNames.size(); - uint64_t DirCount = Content.DirectoryNames.size(); - uint64_t FilesSize = 0; - for (uint64_t FileSize : Content.FileSizes) - { - FilesSize += FileSize; - } - TotalBytes += FilesSize; - TotalFileCount += FileCount; - TotalDirCount += DirCount; - } - - std::atomic_uint64_t TotalBytes = 0; - std::atomic_uint64_t TotalFileCount = 0; - std::atomic_uint64_t TotalDirCount = 0; - - DirStats GetStats() - { - return {.FileCount = TotalFileCount.load(), .DirCount = TotalDirCount.load(), .ByteCount = TotalBytes.load()}; - } - } DirTraverser; - - Latch PendingWorkCount(1); - - GetDirectoryContent(Dir, - DirectoryContentFlags::IncludeAllEntries | DirectoryContentFlags::IncludeFileSizes, - DirTraverser, - GetSmallWorkerPool(EWorkloadType::Background), - PendingWorkCount); - PendingWorkCount.CountDown(); - PendingWorkCount.Wait(); - - return DirTraverser.GetStats(); -} - -struct StateDiskStats -{ - DirStats CacheStats; - DirStats CasStats; - DirStats ProjectStats; -}; - -StateDiskStats -GetStatsForStateDirectory(std::filesystem::path StateDir) -{ - StateDiskStats Stats; - Stats.CacheStats = GetStatsForDirectory(StateDir / "cache"); - Stats.CasStats = GetStatsForDirectory(StateDir / "cas"); - Stats.ProjectStats = GetStatsForDirectory(StateDir / "projects"); - return Stats; -} - -HttpAdminService::HttpAdminService(GcScheduler& Scheduler, - JobQueue& BackgroundJobQueue, - ZenCacheStore* CacheStore, - std::function<void()>&& FlushFunction, - const LogPaths& LogPaths, - const ZenServerOptions& ServerOptions) -: m_GcScheduler(Scheduler) -, m_BackgroundJobQueue(BackgroundJobQueue) -, m_CacheStore(CacheStore) -, m_FlushFunction(std::move(FlushFunction)) -, m_LogPaths(LogPaths) -, m_ServerOptions(ServerOptions) -{ - using namespace std::literals; - - m_Router.RegisterRoute( - "health", - [](HttpRouterRequest& Req) { - CbObjectWriter Obj; - Obj.AddBool("ok", true); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); - - m_Router.AddPattern("jobid", "([[:digit:]]+?)"); - - m_Router.RegisterRoute( - "jobs", - [&](HttpRouterRequest& Req) { - std::vector<JobQueue::JobInfo> Jobs = m_BackgroundJobQueue.GetJobs(); - CbObjectWriter Obj; - Obj.BeginArray("jobs"); - for (const auto& Job : Jobs) - { - Obj.BeginObject(); - Obj.AddInteger("Id", Job.Id.Id); - Obj.AddString("Status", JobQueue::ToString(Job.Status)); - Obj.EndObject(); - } - Obj.EndArray(); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "jobs/{jobid}", - [&](HttpRouterRequest& Req) { - const auto& JobIdString = Req.GetCapture(1); - std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString); - if (!JobIdArg) - { - Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest); - } - JobId Id{.Id = JobIdArg.value_or(0)}; - if (Id.Id == 0) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, - ZenContentType::kText, - fmt::format("Invalid Job Id: {}", Id.Id)); - } - - std::optional<JobQueue::JobDetails> CurrentState = m_BackgroundJobQueue.Get(Id); - if (!CurrentState) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound); - } - - auto WriteState = [](CbObjectWriter& Obj, const JobQueue::State& State) { - if (!State.CurrentOp.empty()) - { - Obj.AddString( - "CurrentOp"sv, - State.CurrentOpDetails.empty() ? State.CurrentOp : fmt::format("{}: {}", State.CurrentOp, State.CurrentOpDetails)); - Obj.AddString("Op"sv, State.CurrentOp); - if (!State.CurrentOpDetails.empty()) - { - Obj.AddString("Details"sv, State.CurrentOpDetails); - } - Obj.AddInteger("TotalCount"sv, gsl::narrow<uint64_t>(State.TotalCount)); - Obj.AddInteger("RemainingCount"sv, gsl::narrow<uint64_t>(State.RemainingCount)); - Obj.AddInteger("CurrentOpPercentComplete"sv, - State.TotalCount > 0 - ? gsl::narrow<uint32_t>((100 * (State.TotalCount - State.RemainingCount)) / State.TotalCount) - : 0); - } - if (!State.Messages.empty()) - { - Obj.BeginArray("Messages"); - for (const std::string& Message : State.Messages) - { - Obj.AddString(Message); - } - Obj.EndArray(); - } - if (!State.AbortReason.empty()) - { - Obj.AddString("AbortReason"sv, State.AbortReason); - } - }; - - auto GetAgeAsSeconds = [](std::chrono::system_clock::time_point Start, std::chrono::system_clock::time_point End) { - auto Age = End - Start; - auto Milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(Age); - return Milliseconds.count() / 1000.0; - }; - - const std::chrono::system_clock::time_point Now = std::chrono::system_clock::now(); - - switch (CurrentState->Status) - { - case JobQueue::Status::Queued: - { - CbObjectWriter Obj; - Obj.AddString("Name"sv, CurrentState->Name); - Obj.AddString("Status"sv, "Queued"sv); - Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, Now)); - Obj.AddInteger("WorkerThread", CurrentState->WorkerThreadId); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - } - break; - case JobQueue::Status::Running: - { - CbObjectWriter Obj; - Obj.AddString("Name"sv, CurrentState->Name); - Obj.AddString("Status"sv, "Running"sv); - WriteState(Obj, CurrentState->State); - Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime)); - Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, Now)); - Obj.AddInteger("WorkerThread", CurrentState->WorkerThreadId); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - } - break; - case JobQueue::Status::Aborted: - { - CbObjectWriter Obj; - Obj.AddString("Name"sv, CurrentState->Name); - Obj.AddString("Status"sv, "Aborted"sv); - - WriteState(Obj, CurrentState->State); - Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime)); - Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime)); - Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now)); - Obj.AddInteger("ReturnCode", CurrentState->ReturnCode); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - } - break; - case JobQueue::Status::Completed: - { - CbObjectWriter Obj; - Obj.AddString("Name"sv, CurrentState->Name); - Obj.AddString("Status"sv, "Complete"sv); - WriteState(Obj, CurrentState->State); - Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime)); - Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime)); - Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now)); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - } - break; - } - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "jobs/{jobid}", - [&](HttpRouterRequest& Req) { - const auto& JobIdString = Req.GetCapture(1); - std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString); - if (!JobIdArg) - { - Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest); - } - JobId Id{.Id = JobIdArg.value_or(0)}; - if (m_BackgroundJobQueue.CancelJob(Id)) - { - Req.ServerRequest().WriteResponse(HttpResponseCode::OK); - } - else - { - Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound); - } - }, - HttpVerb::kDelete); - - m_Router.RegisterRoute( - "gc", - [this](HttpRouterRequest& Req) { - const GcSchedulerState State = m_GcScheduler.GetState(); - - const HttpServerRequest::QueryParams Params = Req.ServerRequest().GetQueryParams(); - - bool Details = false; - if (auto Param = Params.GetValue("details"); Param == "true") - { - Details = true; - } - - CbObjectWriter Response; - Response << "Status"sv << (GcSchedulerStatus::kIdle == State.Status ? "Idle"sv : "Running"sv); - Response.BeginObject("Config"); - { - Response << "RootDirectory" << State.Config.RootDirectory.string(); - Response << "MonitorInterval" << ToTimeSpan(State.Config.MonitorInterval); - Response << "Interval" << ToTimeSpan(State.Config.Interval); - Response << "MaxCacheDuration" << ToTimeSpan(State.Config.MaxCacheDuration); - Response << "MaxProjectStoreDuration" << ToTimeSpan(State.Config.MaxProjectStoreDuration); - Response << "MaxBuildStoreDuration" << ToTimeSpan(State.Config.MaxBuildStoreDuration); - Response << "CollectSmallObjects" << State.Config.CollectSmallObjects; - Response << "Enabled" << State.Config.Enabled; - Response << "DiskReserveSize" << NiceBytes(State.Config.DiskReserveSize); - Response << "DiskSizeSoftLimit" << NiceBytes(State.Config.DiskSizeSoftLimit); - Response << "MinimumFreeDiskSpaceToAllowWrites" << NiceBytes(State.Config.MinimumFreeDiskSpaceToAllowWrites); - Response << "LightweightInterval" << ToTimeSpan(State.Config.LightweightInterval); - Response << "UseGCVersion" << ((State.Config.UseGCVersion == GcVersion::kV1_Deprecated) ? "1" : "2"); - Response << "CompactBlockUsageThresholdPercent" << State.Config.CompactBlockUsageThresholdPercent; - Response << "Verbose" << State.Config.Verbose; - Response << "SingleThreaded" << State.Config.SingleThreaded; - Response << "AttachmentPassCount" << State.Config.AttachmentPassCount; - } - Response.EndObject(); - Response << "AreDiskWritesBlocked" << State.AreDiskWritesBlocked; - Response << "HasDiskReserve" << State.HasDiskReserve; - Response << "DiskSize" << NiceBytes(State.DiskSize); - Response << "DiskUsed" << NiceBytes(State.DiskUsed); - Response << "DiskFree" << NiceBytes(State.DiskFree); - - Response.BeginObject("FullGC"); - { - Response << "LastTime" << ToDateTime(State.LastFullGcTime); - Response << "TimeToNext" << ToTimeSpan(State.RemainingTimeUntilFullGc); - if (State.Config.DiskSizeSoftLimit != 0) - { - Response << "SpaceToNext" << NiceBytes(State.RemainingSpaceUntilFullGC); - } - if (State.LastFullGCV2Result) - { - const bool HumanReadable = true; - WriteGCResult(Response, State.LastFullGCV2Result.value(), HumanReadable, Details); - } - else - { - Response << "LastDuration" << ToTimeSpan(State.LastFullGcDuration); - Response << "LastDiskFreed" << NiceBytes(State.LastFullGCDiff.DiskSize); - Response << "LastMemoryFreed" << NiceBytes(State.LastFullGCDiff.MemorySize); - } - if (State.LastFullAttachmentRangeMin != IoHash::Zero || State.LastFullAttachmentRangeMax != IoHash::Max) - { - Response << "AttachmentRangeMin" << State.LastFullAttachmentRangeMin; - Response << "AttachmentRangeMax" << State.LastFullAttachmentRangeMax; - } - } - Response.EndObject(); - Response.BeginObject("LightweightGC"); - { - Response << "LastTime" << ToDateTime(State.LastLightweightGcTime); - Response << "TimeToNext" << ToTimeSpan(State.RemainingTimeUntilLightweightGc); - - if (State.LastLightweightGCV2Result) - { - const bool HumanReadable = true; - WriteGCResult(Response, State.LastLightweightGCV2Result.value(), HumanReadable, Details); - } - else - { - Response << "LastDuration" << ToTimeSpan(State.LastLightweightGcDuration); - Response << "LastDiskFreed" << NiceBytes(State.LastLightweightGCDiff.DiskSize); - Response << "LastMemoryFreed" << NiceBytes(State.LastLightweightGCDiff.MemorySize); - } - } - Response.EndObject(); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Response.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "gc", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams(); - GcScheduler::TriggerGcParams GcParams; - - if (auto Param = Params.GetValue("smallobjects"); Param.empty() == false) - { - GcParams.CollectSmallObjects = Param == "true"sv; - } - - if (auto Param = Params.GetValue("maxcacheduration"); Param.empty() == false) - { - if (auto Value = ParseInt<uint64_t>(Param)) - { - GcParams.MaxCacheDuration = std::chrono::seconds(Value.value()); - } - } - - if (auto Param = Params.GetValue("maxprojectstoreduration"); Param.empty() == false) - { - if (auto Value = ParseInt<uint64_t>(Param)) - { - GcParams.MaxProjectStoreDuration = std::chrono::seconds(Value.value()); - } - } - - if (auto Param = Params.GetValue("maxbuildstoreduration"); Param.empty() == false) - { - if (auto Value = ParseInt<uint64_t>(Param)) - { - GcParams.MaxBuildStoreDuration = std::chrono::seconds(Value.value()); - } - } - - if (auto Param = Params.GetValue("disksizesoftlimit"); Param.empty() == false) - { - if (auto Value = ParseInt<uint64_t>(Param)) - { - GcParams.DiskSizeSoftLimit = Value.value(); - } - } - - if (auto Param = Params.GetValue("skipcid"); Param.empty() == false) - { - GcParams.SkipCid = Param == "true"sv; - } - - if (auto Param = Params.GetValue("skipdelete"); Param.empty() == false) - { - GcParams.SkipDelete = Param == "true"sv; - } - - if (auto Param = Params.GetValue("forceusegcv1"); Param.empty() == false) - { - GcParams.ForceGCVersion = GcVersion::kV1_Deprecated; - } - - if (auto Param = Params.GetValue("forceusegcv2"); Param.empty() == false) - { - GcParams.ForceGCVersion = GcVersion::kV2; - } - - if (auto Param = Params.GetValue("compactblockthreshold"); Param.empty() == false) - { - if (auto Value = ParseInt<uint32_t>(Param)) - { - GcParams.CompactBlockUsageThresholdPercent = Value.value(); - } - } - - if (auto Param = Params.GetValue("verbose"); Param.empty() == false) - { - GcParams.Verbose = Param == "true"sv; - } - - if (auto Param = Params.GetValue("singlethreaded"); Param.empty() == false) - { - GcParams.SingleThreaded = Param == "true"sv; - } - - if (auto Param = Params.GetValue("referencehashlow"); Param.empty() == false) - { - GcParams.AttachmentRangeMin = IoHash::FromHexString(Param); - } - - if (auto Param = Params.GetValue("referencehashhigh"); Param.empty() == false) - { - GcParams.AttachmentRangeMax = IoHash::FromHexString(Param); - } - - if (auto Param = Params.GetValue("storecacheattachmentmetadata"); Param.empty() == false) - { - GcParams.StoreCacheAttachmentMetaData = Param == "true"sv; - } - - if (auto Param = Params.GetValue("storeprojectattachmentmetadata"); Param.empty() == false) - { - GcParams.StoreProjectAttachmentMetaData = Param == "true"sv; - } - - if (auto Param = Params.GetValue("enablevalidation"); Param.empty() == false) - { - GcParams.EnableValidation = Param == "true"sv; - } - - const bool Started = m_GcScheduler.TriggerGc(GcParams); - - CbObjectWriter Response; - Response << "Status"sv << (Started ? "Started"sv : "Running"sv); - HttpReq.WriteResponse(HttpResponseCode::Accepted, Response.Save()); - }, - HttpVerb::kPost); - - m_Router.RegisterRoute( - "gc-stop", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - if (m_GcScheduler.CancelGC()) - { - return HttpReq.WriteResponse(HttpResponseCode::Accepted); - } - HttpReq.WriteResponse(HttpResponseCode::OK); - }, - HttpVerb::kPost); - -#if ZEN_USE_MIMALLOC - m_Router.RegisterRoute( - "mi_collect", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams(); - - bool Force = false; - - if (auto Param = Params.GetValue("force"); Param.empty() == false) - { - Force = (Param == "true"sv); - } - - ExtendableStringBuilder<256> MiStats; - ExtendableStringBuilder<256> MiStatsAfter; - - auto MiOutputFun = [](const char* msg, void* arg) { - StringBuilderBase* StarsSb = reinterpret_cast<StringBuilderBase*>(arg); - StarsSb->AppendAscii(msg); - }; - - mi_stats_print_out(MiOutputFun, static_cast<StringBuilderBase*>(&MiStats)); - mi_collect(Force); - mi_stats_print_out(MiOutputFun, static_cast<StringBuilderBase*>(&MiStatsAfter)); - - CbObjectWriter Response; - Response << "force"sv << Force; - Response << "stats_before"sv << MiStats; - Response << "stats_after"sv << MiStatsAfter; - HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save()); - }, - HttpVerb::kPost); -#endif - - m_Router.RegisterRoute( - "scrub", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams(); - - GcScheduler::TriggerScrubParams ScrubParams; - ScrubParams.MaxTimeslice = std::chrono::seconds(100); - - if (auto Param = Params.GetValue("skipdelete"); Param.empty() == false) - { - ScrubParams.SkipDelete = (Param == "true"sv); - } - - if (auto Param = Params.GetValue("skipgc"); Param.empty() == false) - { - ScrubParams.SkipGc = (Param == "true"sv); - } - - if (auto Param = Params.GetValue("skipcid"); Param.empty() == false) - { - ScrubParams.SkipCas = (Param == "true"sv); - } - - m_GcScheduler.TriggerScrub(ScrubParams); - - CbObjectWriter Response; - Response << "ok"sv << true; - Response << "skip_delete" << ScrubParams.SkipDelete; - Response << "skip_gc" << ScrubParams.SkipGc; - Response << "skip_cas" << ScrubParams.SkipCas; - Response << "max_time" << TimeSpan(0, 0, gsl::narrow<int>(ScrubParams.MaxTimeslice.count())); - HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save()); - }, - HttpVerb::kPost); - - m_Router.RegisterRoute( - "", - [](HttpRouterRequest& Req) { - CbObject Payload = Req.ServerRequest().ReadPayloadObject(); - - CbObjectWriter Obj; - Obj.AddBool("ok", true); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kPost); - -#if ZEN_WITH_TRACE - m_Router.RegisterRoute( - "trace", - [this](HttpRouterRequest& Req) { - bool Enabled = IsTracing(); - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Enabled ? "enabled" : "disabled"); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "trace/start", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams(); - TraceOptions TraceOptions; - - if (!IsTracing()) - { - TraceInit("zenserver"); - } - - if (auto Channels = Params.GetValue("channels"); Channels.empty() == false) - { - TraceOptions.Channels = Channels; - } - - if (auto File = Params.GetValue("file"); File.empty() == false) - { - TraceOptions.File = File; - } - else if (auto Host = Params.GetValue("host"); Host.empty() == false) - { - TraceOptions.Host = Host; - } - else - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, - HttpContentType::kText, - "Invalid trace type, use `file` or `host`"sv); - } - - TraceConfigure(TraceOptions); - - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, "Tracing started"); - }, - HttpVerb::kPost); - - m_Router.RegisterRoute( - "trace/stop", - [this](HttpRouterRequest& Req) { - if (!IsTracing()) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Tracing is not enabled"sv); - } - if (TraceStop()) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, "Tracing stopped"); - } - else - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::InternalServerError, - HttpContentType::kText, - "Failed stopping trace"); - } - }, - HttpVerb::kPost); -#endif // ZEN_WITH_TRACE - - m_Router.RegisterRoute( - "info", - [this](HttpRouterRequest& Req) { - CbObjectWriter Obj; - - Obj << "root" << m_ServerOptions.SystemRootDir.generic_wstring(); - Obj << "install" << (m_ServerOptions.SystemRootDir / "Install").generic_wstring(); - - Obj.BeginObject("primary"); - Obj << "data" << m_ServerOptions.DataDir.generic_wstring(); - - try - { - auto Stats = GetStatsForStateDirectory(m_ServerOptions.DataDir); - - auto EmitStats = [&](std::string_view Tag, const DirStats& Stats) { - Obj.BeginObject(Tag); - Obj << "bytes" << Stats.ByteCount; - Obj << "files" << Stats.FileCount; - Obj << "dirs" << Stats.DirCount; - Obj.EndObject(); - }; - - EmitStats("cache", Stats.CacheStats); - EmitStats("cas", Stats.CasStats); - EmitStats("project", Stats.ProjectStats); - } - catch (const std::exception& Ex) - { - ZEN_WARN("exception in disk stats gathering for '{}': {}", m_ServerOptions.DataDir, Ex.what()); - } - Obj.EndObject(); - - try - { - std::vector<CbObject> Manifests = ReadAllCentralManifests(m_ServerOptions.SystemRootDir); - - Obj.BeginArray("known"); - - for (const auto& Manifest : Manifests) - { - Obj.AddObject(Manifest); - } - - Obj.EndArray(); - } - catch (const std::exception& Ex) - { - ZEN_WARN("exception in state gathering for '{}': {}", m_ServerOptions.SystemRootDir, Ex.what()); - } - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "logs", - [this](HttpRouterRequest& Req) { - CbObjectWriter Obj; - auto LogLevel = logging::level::ToStringView(logging::GetLogLevel()); - Obj.AddString("loglevel", std::string_view(LogLevel.data(), LogLevel.size())); - Obj.AddString("Logfile", PathToUtf8(m_LogPaths.AbsLogPath)); - Obj.BeginObject("cache"); - if (m_CacheStore) - { - const ZenCacheStore::Configuration& CacheConfig = m_CacheStore->GetConfiguration(); - Obj.AddString("Logfile", PathToUtf8(m_LogPaths.CacheLogPath)); - Obj.AddBool("Write", CacheConfig.Logging.EnableWriteLog); - Obj.AddBool("Access", CacheConfig.Logging.EnableAccessLog); - } - Obj.EndObject(); - Obj.BeginObject("http"); - { - Obj.AddString("Logfile", PathToUtf8(m_LogPaths.HttpLogPath)); - } - Obj.EndObject(); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "logs", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams(); - bool SetCacheLogConfig = false; - ExtendableStringBuilder<256> StringBuilder; - if (m_CacheStore) - { - ZenCacheStore::Configuration::LogConfig LoggingConfig = m_CacheStore->GetConfiguration().Logging; - if (std::string Param(Params.GetValue("cacheenablewritelog")); Param.empty() == false) - { - LoggingConfig.EnableWriteLog = StrCaseCompare(Param.c_str(), "true") == 0; - SetCacheLogConfig = true; - } - if (std::string Param(Params.GetValue("cacheenableaccesslog")); Param.empty() == false) - { - LoggingConfig.EnableAccessLog = StrCaseCompare(Param.c_str(), "true") == 0; - SetCacheLogConfig = true; - } - if (SetCacheLogConfig) - { - m_CacheStore->SetLoggingConfig(LoggingConfig); - StringBuilder.Append(fmt::format("cache write log: {}, cache access log: {}", - LoggingConfig.EnableWriteLog ? "true" : "false", - LoggingConfig.EnableAccessLog ? "true" : "false")); - } - } - if (std::string Param(Params.GetValue("loglevel")); Param.empty() == false) - { - logging::level::LogLevel NewLevel = logging::level::ParseLogLevelString(Param); - std::string_view LogLevel = logging::level::ToStringView(NewLevel); - if (LogLevel != Param) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, - HttpContentType::kText, - fmt::format("Invalid log level '{}'", Param)); - } - logging::SetLogLevel(NewLevel); - if (StringBuilder.Size() > 0) - { - StringBuilder.Append(", "); - } - StringBuilder.Append("loglevel: "); - StringBuilder.Append(Param); - } - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, StringBuilder.ToView()); - }, - HttpVerb::kPost); - m_Router.RegisterRoute( - "flush", - [this](HttpRouterRequest& Req) { - HttpServerRequest& HttpReq = Req.ServerRequest(); - m_FlushFunction(); - HttpReq.WriteResponse(HttpResponseCode::OK); - }, - HttpVerb::kPost); -} - -HttpAdminService::~HttpAdminService() -{ -} - -const char* -HttpAdminService::BaseUri() const -{ - return "/admin/"; -} - -void -HttpAdminService::HandleRequest(zen::HttpServerRequest& Request) -{ - m_Router.HandleRequest(Request); -} - -} // namespace zen |