aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-02-13 13:47:51 +0100
committerGitHub Enterprise <[email protected]>2026-02-13 13:47:51 +0100
commitb0a3de5fec8f4da8f9513b02bc2326aa6a0e7bd5 (patch)
treea365bcd2bd339fc275d19bdc78ea3af0d2437386
parentadd IHttpRequestFilter to allow server implementation to filter/reject reques... (diff)
downloadzen-b0a3de5fec8f4da8f9513b02bc2326aa6a0e7bd5.tar.xz
zen-b0a3de5fec8f4da8f9513b02bc2326aa6a0e7bd5.zip
logging config move to zenutil (#754)
made logging config options from zenserver available in zen CLI
-rw-r--r--CHANGELOG.md1
-rw-r--r--src/zen/zen.cpp23
-rw-r--r--src/zen/zen.h5
-rw-r--r--src/zenserver-test/zenserver-test.cpp2
-rw-r--r--src/zenserver/config/config.cpp73
-rw-r--r--src/zenserver/config/config.h31
-rw-r--r--src/zenserver/config/luaconfig.h2
-rw-r--r--src/zenserver/diag/logging.cpp12
-rw-r--r--src/zenserver/main.cpp2
-rw-r--r--src/zenserver/storage/zenstorageserver.cpp2
-rw-r--r--src/zenserver/zenserver.cpp12
-rw-r--r--src/zenutil/config/commandlineoptions.cpp (renamed from src/zenutil/commandlineoptions.cpp)2
-rw-r--r--src/zenutil/config/environmentoptions.cpp (renamed from src/zenutil/environmentoptions.cpp)2
-rw-r--r--src/zenutil/config/loggingconfig.cpp77
-rw-r--r--src/zenutil/include/zenutil/config/commandlineoptions.h (renamed from src/zenutil/include/zenutil/commandlineoptions.h)0
-rw-r--r--src/zenutil/include/zenutil/config/environmentoptions.h (renamed from src/zenutil/include/zenutil/environmentoptions.h)2
-rw-r--r--src/zenutil/include/zenutil/config/loggingconfig.h37
-rw-r--r--src/zenutil/zenutil.cpp2
18 files changed, 188 insertions, 99 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aaac59c83..487d45fef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
##
- Improvement: Reduced time project and project oplogs are locked during GC and Validation
+- Improvement: `zen` now supports additional configuration of logging options, such as `--log-warn=...` for configuring log levels, etc (see `zen --help`)
## 5.7.20
- Improvement: When validating cache records read from disk we now do a limited validation of the payload to reduce overhead
diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp
index 09a2e4f91..25245c3d2 100644
--- a/src/zen/zen.cpp
+++ b/src/zen/zen.cpp
@@ -39,7 +39,7 @@
#include <zencore/trace.h>
#include <zencore/windows.h>
#include <zenhttp/httpcommon.h>
-#include <zenutil/environmentoptions.h>
+#include <zenutil/config/environmentoptions.h>
#include <zenutil/logging.h>
#include <zenutil/workerpools.h>
#include <zenutil/zenserverprocess.h>
@@ -538,6 +538,9 @@ main(int argc, char** argv)
Options.add_options()("corelimit", "Limit concurrency", cxxopts::value(CoreLimit));
+ ZenLoggingCmdLineOptions LoggingCmdLineOptions;
+ LoggingCmdLineOptions.AddCliOptions(Options, GlobalOptions.LoggingConfig);
+
#if ZEN_WITH_TRACE
// We only have this in options for command line help purposes - we parse these argument separately earlier using
// GetTraceOptionsFromCommandline()
@@ -624,8 +627,8 @@ main(int argc, char** argv)
}
LimitHardwareConcurrency(CoreLimit);
-#if ZEN_USE_SENTRY
+#if ZEN_USE_SENTRY
{
EnvironmentOptions EnvOptions;
@@ -671,12 +674,20 @@ main(int argc, char** argv)
}
#endif
- zen::LoggingOptions LogOptions;
- LogOptions.IsDebug = GlobalOptions.IsDebug;
- LogOptions.IsVerbose = GlobalOptions.IsVerbose;
- LogOptions.AllowAsync = false;
+ LoggingCmdLineOptions.ApplyOptions(GlobalOptions.LoggingConfig);
+
+ const LoggingOptions LogOptions = {.IsDebug = GlobalOptions.IsDebug,
+ .IsVerbose = GlobalOptions.IsVerbose,
+ .IsTest = false,
+ .AllowAsync = false,
+ .NoConsoleOutput = GlobalOptions.LoggingConfig.NoConsoleOutput,
+ .QuietConsole = GlobalOptions.LoggingConfig.QuietConsole,
+ .AbsLogFile = GlobalOptions.LoggingConfig.AbsLogFile,
+ .LogId = GlobalOptions.LoggingConfig.LogId};
zen::InitializeLogging(LogOptions);
+ ApplyLoggingOptions(Options, GlobalOptions.LoggingConfig);
+
std::set_terminate([]() {
void* Frames[8];
uint32_t FrameCount = GetCallstack(2, 8, Frames);
diff --git a/src/zen/zen.h b/src/zen/zen.h
index 05d1e4ec8..e3481beea 100644
--- a/src/zen/zen.h
+++ b/src/zen/zen.h
@@ -5,7 +5,8 @@
#include <zencore/except.h>
#include <zencore/timer.h>
#include <zencore/zencore.h>
-#include <zenutil/commandlineoptions.h>
+#include <zenutil/config/commandlineoptions.h>
+#include <zenutil/config/loggingconfig.h>
namespace zen {
@@ -14,6 +15,8 @@ struct ZenCliOptions
bool IsDebug = false;
bool IsVerbose = false;
+ ZenLoggingConfig LoggingConfig;
+
// Arguments after " -- " on command line are passed through and not parsed
std::string PassthroughCommandLine;
std::string PassthroughArgs;
diff --git a/src/zenserver-test/zenserver-test.cpp b/src/zenserver-test/zenserver-test.cpp
index 9a42bb73d..4120dec1a 100644
--- a/src/zenserver-test/zenserver-test.cpp
+++ b/src/zenserver-test/zenserver-test.cpp
@@ -17,7 +17,7 @@
# include <zencore/timer.h>
# include <zenhttp/httpclient.h>
# include <zenhttp/packageformat.h>
-# include <zenutil/commandlineoptions.h>
+# include <zenutil/config/commandlineoptions.h>
# include <zenutil/logging/testformatter.h>
# include <zenutil/zenserverprocess.h>
diff --git a/src/zenserver/config/config.cpp b/src/zenserver/config/config.cpp
index 07913e891..2b77df642 100644
--- a/src/zenserver/config/config.cpp
+++ b/src/zenserver/config/config.cpp
@@ -16,8 +16,8 @@
#include <zencore/iobuffer.h>
#include <zencore/logging.h>
#include <zencore/string.h>
-#include <zenutil/commandlineoptions.h>
-#include <zenutil/environmentoptions.h>
+#include <zenutil/config/commandlineoptions.h>
+#include <zenutil/config/environmentoptions.h>
ZEN_THIRD_PARTY_INCLUDES_START
#include <fmt/format.h>
@@ -119,10 +119,17 @@ ZenServerConfiguratorBase::AddCommonConfigOptions(LuaConfig::Options& LuaOptions
ZenServerConfig& ServerOptions = m_ServerOptions;
+ // logging
+
+ LuaOptions.AddOption("server.logid"sv, ServerOptions.LoggingConfig.LogId, "log-id"sv);
+ LuaOptions.AddOption("server.abslog"sv, ServerOptions.LoggingConfig.AbsLogFile, "abslog"sv);
+ LuaOptions.AddOption("server.otlpendpoint"sv, ServerOptions.LoggingConfig.OtelEndpointUri, "otlp-endpoint"sv);
+ LuaOptions.AddOption("server.quiet"sv, ServerOptions.LoggingConfig.QuietConsole, "quiet"sv);
+ LuaOptions.AddOption("server.noconsole"sv, ServerOptions.LoggingConfig.NoConsoleOutput, "noconsole"sv);
+
// server
LuaOptions.AddOption("server.dedicated"sv, ServerOptions.IsDedicated, "dedicated"sv);
- LuaOptions.AddOption("server.logid"sv, ServerOptions.LogId, "log-id"sv);
LuaOptions.AddOption("server.sentry.disable"sv, ServerOptions.SentryConfig.Disable, "no-sentry"sv);
LuaOptions.AddOption("server.sentry.allowpersonalinfo"sv, ServerOptions.SentryConfig.AllowPII, "sentry-allow-personal-info"sv);
LuaOptions.AddOption("server.sentry.dsn"sv, ServerOptions.SentryConfig.Dsn, "sentry-dsn"sv);
@@ -131,12 +138,8 @@ ZenServerConfiguratorBase::AddCommonConfigOptions(LuaConfig::Options& LuaOptions
LuaOptions.AddOption("server.systemrootdir"sv, ServerOptions.SystemRootDir, "system-dir"sv);
LuaOptions.AddOption("server.datadir"sv, ServerOptions.DataDir, "data-dir"sv);
LuaOptions.AddOption("server.contentdir"sv, ServerOptions.ContentDir, "content-dir"sv);
- LuaOptions.AddOption("server.abslog"sv, ServerOptions.AbsLogFile, "abslog"sv);
- LuaOptions.AddOption("server.otlpendpoint"sv, ServerOptions.OtelEndpointUri, "otlp-endpoint"sv);
LuaOptions.AddOption("server.debug"sv, ServerOptions.IsDebug, "debug"sv);
LuaOptions.AddOption("server.clean"sv, ServerOptions.IsCleanStart, "clean"sv);
- LuaOptions.AddOption("server.quiet"sv, ServerOptions.QuietConsole, "quiet"sv);
- LuaOptions.AddOption("server.noconsole"sv, ServerOptions.NoConsoleOutput, "noconsole"sv);
////// network
@@ -182,9 +185,10 @@ struct ZenServerCmdLineOptions
std::string SystemRootDir;
std::string ContentDir;
std::string DataDir;
- std::string AbsLogFile;
std::string BaseSnapshotDir;
+ ZenLoggingCmdLineOptions LoggingOptions;
+
void AddCliOptions(cxxopts::Options& options, ZenServerConfig& ServerOptions);
void ApplyOptions(cxxopts::Options& options, ZenServerConfig& ServerOptions);
};
@@ -249,22 +253,7 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
cxxopts::value<bool>(ServerOptions.ShouldCrash)->default_value("false"),
"");
- // clang-format off
- options.add_options("logging")
- ("abslog", "Path to log file", cxxopts::value<std::string>(AbsLogFile))
- ("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(ServerOptions.LogId))
- ("quiet", "Configure console logger output to level WARN", cxxopts::value<bool>(ServerOptions.QuietConsole)->default_value("false"))
- ("noconsole", "Disable console logging", cxxopts::value<bool>(ServerOptions.NoConsoleOutput)->default_value("false"))
- ("log-trace", "Change selected loggers to level TRACE", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Trace]))
- ("log-debug", "Change selected loggers to level DEBUG", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Debug]))
- ("log-info", "Change selected loggers to level INFO", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Info]))
- ("log-warn", "Change selected loggers to level WARN", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Warn]))
- ("log-error", "Change selected loggers to level ERROR", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Err]))
- ("log-critical", "Change selected loggers to level CRITICAL", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Critical]))
- ("log-off", "Change selected loggers to level OFF", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Off]))
- ("otlp-endpoint", "OpenTelemetry endpoint URI (e.g http://localhost:4318)", cxxopts::value<std::string>(ServerOptions.OtelEndpointUri))
- ;
- // clang-format on
+ LoggingOptions.AddCliOptions(options, ServerOptions.LoggingConfig);
options
.add_option("lifetime", "", "owner-pid", "Specify owning process id", cxxopts::value<int>(ServerOptions.OwnerPid), "<identifier>");
@@ -394,9 +383,10 @@ ZenServerCmdLineOptions::ApplyOptions(cxxopts::Options& options, ZenServerConfig
ServerOptions.SystemRootDir = MakeSafeAbsolutePath(SystemRootDir);
ServerOptions.DataDir = MakeSafeAbsolutePath(DataDir);
ServerOptions.ContentDir = MakeSafeAbsolutePath(ContentDir);
- ServerOptions.AbsLogFile = MakeSafeAbsolutePath(AbsLogFile);
ServerOptions.ConfigFile = MakeSafeAbsolutePath(ConfigFile);
ServerOptions.BaseSnapshotDir = MakeSafeAbsolutePath(BaseSnapshotDir);
+
+ LoggingOptions.ApplyOptions(ServerOptions.LoggingConfig);
}
//////////////////////////////////////////////////////////////////////////
@@ -466,34 +456,7 @@ ZenServerConfiguratorBase::Configure(int argc, char* argv[])
}
#endif
- if (m_ServerOptions.QuietConsole)
- {
- bool HasExplicitConsoleLevel = false;
- for (int i = 0; i < logging::level::LogLevelCount; ++i)
- {
- if (m_ServerOptions.Loggers[i].find("console") != std::string::npos)
- {
- HasExplicitConsoleLevel = true;
- break;
- }
- }
-
- if (!HasExplicitConsoleLevel)
- {
- std::string& WarnLoggers = m_ServerOptions.Loggers[logging::level::Warn];
- if (!WarnLoggers.empty())
- {
- WarnLoggers += ",";
- }
- WarnLoggers += "console";
- }
- }
-
- for (int i = 0; i < logging::level::LogLevelCount; ++i)
- {
- logging::ConfigureLogLevels(logging::level::LogLevel(i), m_ServerOptions.Loggers[i]);
- }
- logging::RefreshLogLevels();
+ ApplyLoggingOptions(options, m_ServerOptions.LoggingConfig);
BaseOptions.ApplyOptions(options, m_ServerOptions);
ApplyOptions(options);
@@ -532,9 +495,9 @@ ZenServerConfiguratorBase::Configure(int argc, char* argv[])
m_ServerOptions.DataDir = PickDefaultStateDirectory(m_ServerOptions.SystemRootDir);
}
- if (m_ServerOptions.AbsLogFile.empty())
+ if (m_ServerOptions.LoggingConfig.AbsLogFile.empty())
{
- m_ServerOptions.AbsLogFile = m_ServerOptions.DataDir / "logs" / "zenserver.log";
+ m_ServerOptions.LoggingConfig.AbsLogFile = m_ServerOptions.DataDir / "logs" / "zenserver.log";
}
m_ServerOptions.HttpConfig.IsDedicatedServer = m_ServerOptions.IsDedicated;
diff --git a/src/zenserver/config/config.h b/src/zenserver/config/config.h
index 7c3192a1f..32c22cb05 100644
--- a/src/zenserver/config/config.h
+++ b/src/zenserver/config/config.h
@@ -6,6 +6,7 @@
#include <zencore/trace.h>
#include <zencore/zencore.h>
#include <zenhttp/httpserver.h>
+#include <zenutil/config/loggingconfig.h>
#include <filesystem>
#include <string>
#include <vector>
@@ -42,29 +43,25 @@ struct ZenServerConfig
HttpServerConfig HttpConfig;
ZenSentryConfig SentryConfig;
ZenStatsConfig StatsConfig;
- int BasePort = 8558; // Service listen port (used for both UDP and TCP)
- int OwnerPid = 0; // Parent process id (zero for standalone)
- bool IsDebug = false;
- bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
- bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
- bool IsTest = false;
- bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
- bool NoConsoleOutput = false; // Control default use of stdout for diagnostics
- bool QuietConsole = false; // Configure console logger output to level WARN
- int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
- bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
- bool ShouldCrash = false; // Option for testing crash handling
- bool IsFirstRun = false;
+ ZenLoggingConfig LoggingConfig;
+ int BasePort = 8558; // Service listen port (used for both UDP and TCP)
+ int OwnerPid = 0; // Parent process id (zero for standalone)
+ bool IsDebug = false;
+ bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
+ bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
+ bool IsTest = false;
+ bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
+ int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
+ int LieCpu = 0;
+ bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
+ bool ShouldCrash = false; // Option for testing crash handling
+ bool IsFirstRun = false;
std::filesystem::path ConfigFile; // Path to Lua config file
std::filesystem::path SystemRootDir; // System root directory (used for machine level config)
std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
std::filesystem::path DataDir; // Root directory for state (used for testing)
- std::filesystem::path AbsLogFile; // Absolute path to main log file
std::filesystem::path BaseSnapshotDir; // Path to server state snapshot (will be copied into data dir on start)
std::string ChildId; // Id assigned by parent process (used for lifetime management)
- std::string LogId; // Id for tagging log output
- std::string Loggers[zen::logging::level::LogLevelCount];
- std::string OtelEndpointUri; // OpenTelemetry endpoint URI
#if ZEN_WITH_TRACE
bool HasTraceCommandlineOptions = false;
diff --git a/src/zenserver/config/luaconfig.h b/src/zenserver/config/luaconfig.h
index ce7013a9a..e3ac3b343 100644
--- a/src/zenserver/config/luaconfig.h
+++ b/src/zenserver/config/luaconfig.h
@@ -4,7 +4,7 @@
#include <zenbase/concepts.h>
#include <zencore/fmtutils.h>
-#include <zenutil/commandlineoptions.h>
+#include <zenutil/config/commandlineoptions.h>
ZEN_THIRD_PARTY_INCLUDES_START
#include <fmt/format.h>
diff --git a/src/zenserver/diag/logging.cpp b/src/zenserver/diag/logging.cpp
index 4962b9006..75a8efc09 100644
--- a/src/zenserver/diag/logging.cpp
+++ b/src/zenserver/diag/logging.cpp
@@ -28,10 +28,10 @@ InitializeServerLogging(const ZenServerConfig& InOptions, bool WithCacheService)
const LoggingOptions LogOptions = {.IsDebug = InOptions.IsDebug,
.IsVerbose = false,
.IsTest = InOptions.IsTest,
- .NoConsoleOutput = InOptions.NoConsoleOutput,
- .QuietConsole = InOptions.QuietConsole,
- .AbsLogFile = InOptions.AbsLogFile,
- .LogId = InOptions.LogId};
+ .NoConsoleOutput = InOptions.LoggingConfig.NoConsoleOutput,
+ .QuietConsole = InOptions.LoggingConfig.QuietConsole,
+ .AbsLogFile = InOptions.LoggingConfig.AbsLogFile,
+ .LogId = InOptions.LoggingConfig.LogId};
BeginInitializeLogging(LogOptions);
@@ -79,10 +79,10 @@ InitializeServerLogging(const ZenServerConfig& InOptions, bool WithCacheService)
}
#if ZEN_WITH_OTEL
- if (!InOptions.OtelEndpointUri.empty())
+ if (!InOptions.LoggingConfig.OtelEndpointUri.empty())
{
// TODO: Should sanity check that endpoint is reachable? Also, a valid URI?
- auto OtelSink = std::make_shared<zen::logging::OtelHttpProtobufSink>(InOptions.OtelEndpointUri);
+ auto OtelSink = std::make_shared<zen::logging::OtelHttpProtobufSink>(InOptions.LoggingConfig.OtelEndpointUri);
zen::logging::Default().SpdLogger->sinks().push_back(std::move(OtelSink));
}
#endif
diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp
index 3a58d1f4a..1a929b026 100644
--- a/src/zenserver/main.cpp
+++ b/src/zenserver/main.cpp
@@ -19,7 +19,7 @@
#include <zencore/thread.h>
#include <zencore/trace.h>
#include <zentelemetry/otlptrace.h>
-#include <zenutil/commandlineoptions.h>
+#include <zenutil/config/commandlineoptions.h>
#include <zenutil/service.h>
#include "diag/logging.h"
diff --git a/src/zenserver/storage/zenstorageserver.cpp b/src/zenserver/storage/zenstorageserver.cpp
index b2cae6482..2b74395c3 100644
--- a/src/zenserver/storage/zenstorageserver.cpp
+++ b/src/zenserver/storage/zenstorageserver.cpp
@@ -305,7 +305,7 @@ ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions
*m_JobQueue,
m_CacheStore.Get(),
[this]() { Flush(); },
- HttpAdminService::LogPaths{.AbsLogPath = ServerOptions.AbsLogFile,
+ HttpAdminService::LogPaths{.AbsLogPath = ServerOptions.LoggingConfig.AbsLogFile,
.HttpLogPath = ServerOptions.DataDir / "logs" / "http.log",
.CacheLogPath = ServerOptions.DataDir / "logs" / "z$.log"},
ServerOptions);
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<std::pair<std::string_view, std::string>> 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,
diff --git a/src/zenutil/commandlineoptions.cpp b/src/zenutil/config/commandlineoptions.cpp
index d94564843..84c718ecc 100644
--- a/src/zenutil/commandlineoptions.cpp
+++ b/src/zenutil/config/commandlineoptions.cpp
@@ -1,6 +1,6 @@
// Copyright Epic Games, Inc. All Rights Reserved.
-#include <zenutil/commandlineoptions.h>
+#include <zenutil/config/commandlineoptions.h>
#include <zencore/string.h>
#include <filesystem>
diff --git a/src/zenutil/environmentoptions.cpp b/src/zenutil/config/environmentoptions.cpp
index ee40086c1..fb7f71706 100644
--- a/src/zenutil/environmentoptions.cpp
+++ b/src/zenutil/config/environmentoptions.cpp
@@ -1,6 +1,6 @@
// Copyright Epic Games, Inc. All Rights Reserved.
-#include <zenutil/environmentoptions.h>
+#include <zenutil/config/environmentoptions.h>
#include <zencore/filesystem.h>
diff --git a/src/zenutil/config/loggingconfig.cpp b/src/zenutil/config/loggingconfig.cpp
new file mode 100644
index 000000000..9ec816b1b
--- /dev/null
+++ b/src/zenutil/config/loggingconfig.cpp
@@ -0,0 +1,77 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "zenutil/config/loggingconfig.h"
+
+#include <zenbase/zenbase.h>
+#include <zencore/filesystem.h>
+#include <zencore/logging.h>
+
+ZEN_THIRD_PARTY_INCLUDES_START
+#include <cxxopts.hpp>
+ZEN_THIRD_PARTY_INCLUDES_END
+
+namespace zen {
+
+void
+ZenLoggingCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenLoggingConfig& LoggingConfig)
+{
+ // clang-format off
+ options.add_options("logging")
+ ("abslog", "Path to log file", cxxopts::value<std::string>(m_AbsLogFile))
+ ("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(LoggingConfig.LogId))
+ ("quiet", "Configure console logger output to level WARN", cxxopts::value<bool>(LoggingConfig.QuietConsole)->default_value("false"))
+ ("noconsole", "Disable console logging", cxxopts::value<bool>(LoggingConfig.NoConsoleOutput)->default_value("false"))
+ ("log-trace", "Change selected loggers to level TRACE", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Trace]))
+ ("log-debug", "Change selected loggers to level DEBUG", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Debug]))
+ ("log-info", "Change selected loggers to level INFO", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Info]))
+ ("log-warn", "Change selected loggers to level WARN", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Warn]))
+ ("log-error", "Change selected loggers to level ERROR", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Err]))
+ ("log-critical", "Change selected loggers to level CRITICAL", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Critical]))
+ ("log-off", "Change selected loggers to level OFF", cxxopts::value<std::string>(LoggingConfig.Loggers[logging::level::Off]))
+ ("otlp-endpoint", "OpenTelemetry endpoint URI (e.g http://localhost:4318)", cxxopts::value<std::string>(LoggingConfig.OtelEndpointUri))
+ ;
+ // clang-format on
+}
+
+void
+ZenLoggingCmdLineOptions::ApplyOptions(ZenLoggingConfig& LoggingConfig)
+{
+ LoggingConfig.AbsLogFile = MakeSafeAbsolutePath(m_AbsLogFile);
+}
+
+void
+ApplyLoggingOptions(cxxopts::Options& options, ZenLoggingConfig& LoggingConfig)
+{
+ ZEN_UNUSED(options);
+
+ if (LoggingConfig.QuietConsole)
+ {
+ bool HasExplicitConsoleLevel = false;
+ for (int i = 0; i < logging::level::LogLevelCount; ++i)
+ {
+ if (LoggingConfig.Loggers[i].find("console") != std::string::npos)
+ {
+ HasExplicitConsoleLevel = true;
+ break;
+ }
+ }
+
+ if (!HasExplicitConsoleLevel)
+ {
+ std::string& WarnLoggers = LoggingConfig.Loggers[logging::level::Warn];
+ if (!WarnLoggers.empty())
+ {
+ WarnLoggers += ",";
+ }
+ WarnLoggers += "console";
+ }
+ }
+
+ for (int i = 0; i < logging::level::LogLevelCount; ++i)
+ {
+ logging::ConfigureLogLevels(logging::level::LogLevel(i), LoggingConfig.Loggers[i]);
+ }
+ logging::RefreshLogLevels();
+}
+
+} // namespace zen
diff --git a/src/zenutil/include/zenutil/commandlineoptions.h b/src/zenutil/include/zenutil/config/commandlineoptions.h
index 01cceedb1..01cceedb1 100644
--- a/src/zenutil/include/zenutil/commandlineoptions.h
+++ b/src/zenutil/include/zenutil/config/commandlineoptions.h
diff --git a/src/zenutil/include/zenutil/environmentoptions.h b/src/zenutil/include/zenutil/config/environmentoptions.h
index 7418608e4..1ecdf591a 100644
--- a/src/zenutil/include/zenutil/environmentoptions.h
+++ b/src/zenutil/include/zenutil/config/environmentoptions.h
@@ -3,7 +3,7 @@
#pragma once
#include <zencore/string.h>
-#include <zenutil/commandlineoptions.h>
+#include <zenutil/config/commandlineoptions.h>
namespace zen {
diff --git a/src/zenutil/include/zenutil/config/loggingconfig.h b/src/zenutil/include/zenutil/config/loggingconfig.h
new file mode 100644
index 000000000..6d6f64b30
--- /dev/null
+++ b/src/zenutil/include/zenutil/config/loggingconfig.h
@@ -0,0 +1,37 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include <zencore/logbase.h>
+#include <filesystem>
+#include <string>
+
+namespace cxxopts {
+class Options;
+}
+
+namespace zen {
+
+struct ZenLoggingConfig
+{
+ bool NoConsoleOutput = false; // Control default use of stdout for diagnostics
+ bool QuietConsole = false; // Configure console logger output to level WARN
+ std::filesystem::path AbsLogFile; // Absolute path to main log file
+ std::string Loggers[logging::level::LogLevelCount];
+ std::string LogId; // Id for tagging log output
+ std::string OtelEndpointUri; // OpenTelemetry endpoint URI
+};
+
+void ApplyLoggingOptions(cxxopts::Options& options, ZenLoggingConfig& LoggingConfig);
+
+class ZenLoggingCmdLineOptions
+{
+public:
+ void AddCliOptions(cxxopts::Options& options, ZenLoggingConfig& LoggingConfig);
+ void ApplyOptions(ZenLoggingConfig& LoggingConfig);
+
+private:
+ std::string m_AbsLogFile;
+};
+
+} // namespace zen
diff --git a/src/zenutil/zenutil.cpp b/src/zenutil/zenutil.cpp
index 51c1ee72e..291dbeadd 100644
--- a/src/zenutil/zenutil.cpp
+++ b/src/zenutil/zenutil.cpp
@@ -5,7 +5,7 @@
#if ZEN_WITH_TESTS
# include <zenutil/rpcrecording.h>
-# include <zenutil/commandlineoptions.h>
+# include <zenutil/config/commandlineoptions.h>
# include <zenutil/wildcard.h>
namespace zen {