From b0a3de5fec8f4da8f9513b02bc2326aa6a0e7bd5 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 13 Feb 2026 13:47:51 +0100 Subject: logging config move to zenutil (#754) made logging config options from zenserver available in zen CLI --- src/zenserver/zenserver.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/zenserver/zenserver.cpp') diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 2bafeeaa1..d54357368 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -152,7 +152,7 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: } m_HealthService.SetHealthInfo({.DataRoot = ServerOptions.DataDir, - .AbsLogPath = ServerOptions.AbsLogFile, + .AbsLogPath = ServerOptions.LoggingConfig.AbsLogFile, .HttpServerClass = std::string(ServerOptions.HttpConfig.ServerClass), .BuildVersion = std::string(ZEN_CFG_VERSION_BUILD_STRING_FULL)}); @@ -387,7 +387,7 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) // clang-format off std::list> Settings = { {"DataDir"sv, ServerConfig.DataDir.string()}, - {"AbsLogFile"sv, ServerConfig.AbsLogFile.string()}, + {"AbsLogFile"sv, ServerConfig.LoggingConfig.AbsLogFile.string()}, {"SystemRootDir"sv, ServerConfig.SystemRootDir.string()}, {"ContentDir"sv, ServerConfig.ContentDir.string()}, {"BasePort"sv, fmt::to_string(ServerConfig.BasePort)}, @@ -396,13 +396,13 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) {"IsPowerCycle"sv, fmt::to_string(ServerConfig.IsPowerCycle)}, {"IsTest"sv, fmt::to_string(ServerConfig.IsTest)}, {"Detach"sv, fmt::to_string(ServerConfig.Detach)}, - {"NoConsoleOutput"sv, fmt::to_string(ServerConfig.NoConsoleOutput)}, - {"QuietConsole"sv, fmt::to_string(ServerConfig.QuietConsole)}, + {"NoConsoleOutput"sv, fmt::to_string(ServerConfig.LoggingConfig.NoConsoleOutput)}, + {"QuietConsole"sv, fmt::to_string(ServerConfig.LoggingConfig.QuietConsole)}, {"CoreLimit"sv, fmt::to_string(ServerConfig.CoreLimit)}, {"IsDedicated"sv, fmt::to_string(ServerConfig.IsDedicated)}, {"ShouldCrash"sv, fmt::to_string(ServerConfig.ShouldCrash)}, {"ChildId"sv, ServerConfig.ChildId}, - {"LogId"sv, ServerConfig.LogId}, + {"LogId"sv, ServerConfig.LoggingConfig.LogId}, {"Sentry DSN"sv, ServerConfig.SentryConfig.Dsn.empty() ? "not set" : ServerConfig.SentryConfig.Dsn}, {"Sentry Environment"sv, ServerConfig.SentryConfig.Environment}, {"Statsd Enabled"sv, fmt::to_string(ServerConfig.StatsConfig.Enabled)}, @@ -467,7 +467,7 @@ ZenServerMain::Run() ZEN_OTEL_SPAN("SentryInit"); std::string SentryDatabasePath = (m_ServerOptions.DataDir / ".sentry-native").string(); - std::string SentryAttachmentPath = m_ServerOptions.AbsLogFile.string(); + std::string SentryAttachmentPath = m_ServerOptions.LoggingConfig.AbsLogFile.string(); Sentry.Initialize({.DatabasePath = SentryDatabasePath, .AttachmentsPath = SentryAttachmentPath, -- cgit v1.2.3 From 5e1e23e209eec75a396c18f8eee3d93a9e196bfc Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Tue, 17 Feb 2026 14:00:53 +0100 Subject: add http server root password protection (#757) - Feature: Added `--security-config-path` option to zenserver to configure security settings - Expects a path to a .json file - Default is an empty path resulting in no extra security settings and legacy behavior - Current support is a top level filter of incoming http requests restricted to the `password` type - `password` type will check the `Authorization` header and match it to the selected authorization strategy - Currently the security settings is very basic and configured to a fixed username+password at startup { "http" { "root": { "filter": { "type": "password", "config": { "password": { "username": "", "password": "" }, "protect-machine-local-requests": false, "unprotected-uris": [ "/health/", "/health/info", "/health/version" ] } } } } } --- src/zenserver/zenserver.cpp | 50 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'src/zenserver/zenserver.cpp') diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index d54357368..7f9bf56a9 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,8 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: ZEN_INFO("Effective concurrency: {} (hw: {})", GetHardwareConcurrency(), std::thread::hardware_concurrency()); + InitializeSecuritySettings(ServerOptions); + m_StatusService.RegisterHandler("status", *this); m_Http->RegisterService(m_StatusService); @@ -386,10 +389,10 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) { // clang-format off std::list> Settings = { - {"DataDir"sv, ServerConfig.DataDir.string()}, - {"AbsLogFile"sv, ServerConfig.LoggingConfig.AbsLogFile.string()}, - {"SystemRootDir"sv, ServerConfig.SystemRootDir.string()}, - {"ContentDir"sv, ServerConfig.ContentDir.string()}, + {"DataDir"sv, fmt::format("{}", ServerConfig.DataDir)}, + {"AbsLogFile"sv, fmt::format("{}", ServerConfig.LoggingConfig.AbsLogFile)}, + {"SystemRootDir"sv, fmt::format("{}", ServerConfig.SystemRootDir)}, + {"ContentDir"sv, fmt::format("{}", ServerConfig.ContentDir)}, {"BasePort"sv, fmt::to_string(ServerConfig.BasePort)}, {"IsDebug"sv, fmt::to_string(ServerConfig.IsDebug)}, {"IsCleanStart"sv, fmt::to_string(ServerConfig.IsCleanStart)}, @@ -406,6 +409,7 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) {"Sentry DSN"sv, ServerConfig.SentryConfig.Dsn.empty() ? "not set" : ServerConfig.SentryConfig.Dsn}, {"Sentry Environment"sv, ServerConfig.SentryConfig.Environment}, {"Statsd Enabled"sv, fmt::to_string(ServerConfig.StatsConfig.Enabled)}, + {"SecurityConfigPath"sv, fmt::format("{}", ServerConfig.SecurityConfigPath)}, }; // clang-format on @@ -432,6 +436,44 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) } } +void +ZenServerBase::InitializeSecuritySettings(const ZenServerConfig& ServerOptions) +{ + ZEN_ASSERT(m_Http); + + if (!ServerOptions.SecurityConfigPath.empty()) + { + IoBuffer SecurityJson = ReadFile(ServerOptions.SecurityConfigPath).Flatten(); + std::string_view Json(reinterpret_cast(SecurityJson.GetData()), SecurityJson.GetSize()); + std::string JsonError; + CbObject SecurityConfig = LoadCompactBinaryFromJson(Json, JsonError).AsObject(); + if (!JsonError.empty()) + { + throw std::runtime_error( + fmt::format("Invalid security configuration file at {}. '{}'", ServerOptions.SecurityConfigPath, JsonError)); + } + + CbObjectView HttpRootFilterConfig = SecurityConfig["http"sv].AsObjectView()["root"sv].AsObjectView()["filter"sv].AsObjectView(); + if (HttpRootFilterConfig) + { + std::string_view FilterType = HttpRootFilterConfig["type"sv].AsString(); + if (FilterType == PasswordHttpFilter::TypeName) + { + PasswordHttpFilter::Configuration Config = + PasswordHttpFilter::ReadConfiguration(HttpRootFilterConfig["config"].AsObjectView()); + m_HttpRequestFilter = std::make_unique(Config); + m_Http->SetHttpRequestFilter(m_HttpRequestFilter.get()); + } + else + { + throw std::runtime_error(fmt::format("Security configuration file at {} references unknown http root filter type '{}'", + ServerOptions.SecurityConfigPath, + FilterType)); + } + } + } +} + ////////////////////////////////////////////////////////////////////////// ZenServerMain::ZenServerMain(ZenServerConfig& ServerOptions) : m_ServerOptions(ServerOptions) -- cgit v1.2.3 From 149a5c2faa8d59290b8b44717e504532e906aae2 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Wed, 18 Feb 2026 11:28:03 +0100 Subject: structured compute basics (#714) this change adds the `zencompute` component, which can be used to distribute work dispatched from UE using the DDB (Derived Data Build) APIs via zenserver this change also adds a distinct zenserver compute mode (`zenserver compute`) which is intended to be used for leaf compute nodes to exercise the compute functionality without directly involving UE, a `zen exec` subcommand is also added, which can be used to feed replays through the system all new functionality is considered *experimental* and disabled by default at this time, behind the `zencompute` option in xmake config --- src/zenserver/zenserver.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/zenserver/zenserver.cpp') diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 7f9bf56a9..7bf6126df 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -145,6 +146,13 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: InitializeSecuritySettings(ServerOptions); + if (ServerOptions.LieCpu) + { + SetCpuCountForReporting(ServerOptions.LieCpu); + + ZEN_INFO("Reporting concurrency: {}", ServerOptions.LieCpu); + } + m_StatusService.RegisterHandler("status", *this); m_Http->RegisterService(m_StatusService); -- cgit v1.2.3 From ee26e5af2ced0987fbdf666dc6bce7c2074e925f Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 20 Feb 2026 09:05:23 +0100 Subject: GC - fix handling of attachment ranges, http access token expiration, lock file retry logic (#766) * GC - fix handling of attachment ranges * fix trace/log strings * fix HTTP access token expiration time logic * added missing lock retry in zenserver startup --- src/zenserver/zenserver.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/zenserver/zenserver.cpp') diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 7bf6126df..5fd35d9b4 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -617,6 +617,8 @@ ZenServerMain::Run() { ZEN_INFO(ZEN_APP_NAME " unable to grab lock at '{}' (reason: '{}'), retrying", LockFilePath, Ec.message()); Sleep(500); + + m_LockFile.Create(LockFilePath, MakeLockData(false), Ec); if (Ec) { ZEN_WARN(ZEN_APP_NAME " exiting, unable to grab lock at '{}' (reason: '{}')", LockFilePath, Ec.message()); -- cgit v1.2.3 From b37b34ea6ad906f54e8104526e77ba66aed997da Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 9 Mar 2026 17:43:08 +0100 Subject: Dashboard overhaul, compute integration (#814) - **Frontend dashboard overhaul**: Unified compute/main dashboards into a single shared UI. Added new pages for cache, projects, metrics, sessions, info (build/runtime config, system stats). Added live-update via WebSockets with pause control, sortable detail tables, themed styling. Refactored compute/hub/orchestrator pages into modular JS. - **HTTP server fixes and stats**: Fixed http.sys local-only fallback when default port is in use, implemented root endpoint redirect for http.sys, fixed Linux/Mac port reuse. Added /stats endpoint exposing HTTP server metrics (bytes transferred, request rates). Added WebSocket stats tracking. - **OTEL/diagnostics hardening**: Improved OTLP HTTP exporter with better error handling and resilience. Extended diagnostics services configuration. - **Session management**: Added new sessions service with HTTP endpoints for registering, updating, querying, and removing sessions. Includes session log file support. This is still WIP. - **CLI subcommand support**: Added support for commands with subcommands in the zen CLI tool, with improved command dispatch. - **Misc**: Exposed CPU usage/hostname to frontend, fixed JS compact binary float32/float64 decoding, limited projects displayed on front page to 25 sorted by last access, added vscode:// link support. Also contains some fixes from TSAN analysis. --- src/zenserver/zenserver.cpp | 103 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 14 deletions(-) (limited to 'src/zenserver/zenserver.cpp') diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 5fd35d9b4..bb6b02d21 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -46,6 +46,20 @@ ZEN_THIRD_PARTY_INCLUDES_END ////////////////////////////////////////////////////////////////////////// +#ifndef ZEN_WITH_COMPUTE_SERVICES +# define ZEN_WITH_COMPUTE_SERVICES 0 +#endif + +#ifndef ZEN_WITH_HORDE +# define ZEN_WITH_HORDE 0 +#endif + +#ifndef ZEN_WITH_NOMAD +# define ZEN_WITH_NOMAD 0 +#endif + +////////////////////////////////////////////////////////////////////////// + #include "config/config.h" #include "diag/logging.h" @@ -155,6 +169,7 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: m_StatusService.RegisterHandler("status", *this); m_Http->RegisterService(m_StatusService); + m_Http->RegisterService(m_StatsService); m_StatsReporter.Initialize(ServerOptions.StatsConfig); if (ServerOptions.StatsConfig.Enabled) @@ -162,10 +177,37 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: EnqueueStatsReportingTimer(); } - m_HealthService.SetHealthInfo({.DataRoot = ServerOptions.DataDir, - .AbsLogPath = ServerOptions.LoggingConfig.AbsLogFile, - .HttpServerClass = std::string(ServerOptions.HttpConfig.ServerClass), - .BuildVersion = std::string(ZEN_CFG_VERSION_BUILD_STRING_FULL)}); + // clang-format off + HealthServiceInfo HealthInfo { + .DataRoot = ServerOptions.DataDir, + .AbsLogPath = ServerOptions.LoggingConfig.AbsLogFile, + .HttpServerClass = std::string(ServerOptions.HttpConfig.ServerClass), + .BuildVersion = std::string(ZEN_CFG_VERSION_BUILD_STRING_FULL), + .Port = EffectiveBasePort, + .Pid = GetCurrentProcessId(), + .IsDedicated = ServerOptions.IsDedicated, + .StartTimeMs = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(), + .BuildOptions = { + {"ZEN_ADDRESS_SANITIZER", ZEN_ADDRESS_SANITIZER != 0}, + {"ZEN_USE_SENTRY", ZEN_USE_SENTRY != 0}, + {"ZEN_WITH_TESTS", ZEN_WITH_TESTS != 0}, + {"ZEN_USE_MIMALLOC", ZEN_USE_MIMALLOC != 0}, + {"ZEN_USE_RPMALLOC", ZEN_USE_RPMALLOC != 0}, + {"ZEN_WITH_HTTPSYS", ZEN_WITH_HTTPSYS != 0}, + {"ZEN_WITH_MEMTRACK", ZEN_WITH_MEMTRACK != 0}, + {"ZEN_WITH_TRACE", ZEN_WITH_TRACE != 0}, + {"ZEN_WITH_COMPUTE_SERVICES", ZEN_WITH_COMPUTE_SERVICES != 0}, + {"ZEN_WITH_HORDE", ZEN_WITH_HORDE != 0}, + {"ZEN_WITH_NOMAD", ZEN_WITH_NOMAD != 0}, + }, + .RuntimeConfig = BuildSettingsList(ServerOptions), + }; + // clang-format on + + HealthInfo.RuntimeConfig.emplace(HealthInfo.RuntimeConfig.begin() + 2, "EffectivePort"sv, fmt::to_string(EffectiveBasePort)); + + m_HealthService.SetHealthInfo(std::move(HealthInfo)); LogSettingsSummary(ServerOptions); @@ -175,11 +217,22 @@ ZenServerBase::Initialize(const ZenServerConfig& ServerOptions, ZenServerState:: void ZenServerBase::Finalize() { + m_StatsService.RegisterHandler("http", *m_Http); + + m_Http->SetDefaultRedirect("/dashboard/"); + // Register health service last so if we return "OK" for health it means all services have been properly initialized m_Http->RegisterService(m_HealthService); } +void +ZenServerBase::ShutdownServices() +{ + m_StatsService.UnregisterHandler("http", *m_Http); + m_StatsService.Shutdown(); +} + void ZenServerBase::GetBuildOptions(StringBuilderBase& OutOptions, char Separator) const { @@ -386,22 +439,25 @@ ZenServerBase::CheckSigInt() void ZenServerBase::HandleStatusRequest(HttpServerRequest& Request) { + auto Metrics = m_MetricsTracker.Query(); + CbObjectWriter Cbo; Cbo << "ok" << true; Cbo << "state" << ToString(m_CurrentState); + Cbo << "hostname" << GetMachineName(); + Cbo << "cpuUsagePercent" << Metrics.CpuUsagePercent; Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); } -void -ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) +std::vector> +ZenServerBase::BuildSettingsList(const ZenServerConfig& ServerConfig) { // clang-format off - std::list> Settings = { - {"DataDir"sv, fmt::format("{}", ServerConfig.DataDir)}, - {"AbsLogFile"sv, fmt::format("{}", ServerConfig.LoggingConfig.AbsLogFile)}, + std::vector> Settings = { {"SystemRootDir"sv, fmt::format("{}", ServerConfig.SystemRootDir)}, {"ContentDir"sv, fmt::format("{}", ServerConfig.ContentDir)}, {"BasePort"sv, fmt::to_string(ServerConfig.BasePort)}, + {"CoreLimit"sv, fmt::to_string(ServerConfig.CoreLimit)}, {"IsDebug"sv, fmt::to_string(ServerConfig.IsDebug)}, {"IsCleanStart"sv, fmt::to_string(ServerConfig.IsCleanStart)}, {"IsPowerCycle"sv, fmt::to_string(ServerConfig.IsPowerCycle)}, @@ -409,9 +465,6 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) {"Detach"sv, fmt::to_string(ServerConfig.Detach)}, {"NoConsoleOutput"sv, fmt::to_string(ServerConfig.LoggingConfig.NoConsoleOutput)}, {"QuietConsole"sv, fmt::to_string(ServerConfig.LoggingConfig.QuietConsole)}, - {"CoreLimit"sv, fmt::to_string(ServerConfig.CoreLimit)}, - {"IsDedicated"sv, fmt::to_string(ServerConfig.IsDedicated)}, - {"ShouldCrash"sv, fmt::to_string(ServerConfig.ShouldCrash)}, {"ChildId"sv, ServerConfig.ChildId}, {"LogId"sv, ServerConfig.LoggingConfig.LogId}, {"Sentry DSN"sv, ServerConfig.SentryConfig.Dsn.empty() ? "not set" : ServerConfig.SentryConfig.Dsn}, @@ -423,10 +476,28 @@ ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) if (ServerConfig.StatsConfig.Enabled) { - Settings.emplace_back("Statsd Host", ServerConfig.StatsConfig.StatsdHost); - Settings.emplace_back("Statsd Port", fmt::to_string(ServerConfig.StatsConfig.StatsdPort)); + Settings.emplace_back("Statsd Host"sv, ServerConfig.StatsConfig.StatsdHost); + Settings.emplace_back("Statsd Port"sv, fmt::to_string(ServerConfig.StatsConfig.StatsdPort)); } + return Settings; +} + +void +ZenServerBase::LogSettingsSummary(const ZenServerConfig& ServerConfig) +{ + auto Settings = BuildSettingsList(ServerConfig); + + // Log-only entries not needed in RuntimeConfig + // clang-format off + Settings.insert(Settings.begin(), { + {"DataDir"sv, fmt::format("{}", ServerConfig.DataDir)}, + {"AbsLogFile"sv, fmt::format("{}", ServerConfig.LoggingConfig.AbsLogFile)}, + }); + // clang-format on + Settings.emplace_back("IsDedicated"sv, fmt::to_string(ServerConfig.IsDedicated)); + Settings.emplace_back("ShouldCrash"sv, fmt::to_string(ServerConfig.ShouldCrash)); + size_t MaxWidth = 0; for (const auto& Setting : Settings) { @@ -674,6 +745,10 @@ ZenServerMain::Run() RequestApplicationExit(1); } +#if ZEN_USE_SENTRY + Sentry.Close(); +#endif + ShutdownServerLogging(); ReportServiceStatus(ServiceStatus::Stopped); -- cgit v1.2.3