aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-09 10:50:47 +0100
committerGitHub Enterprise <[email protected]>2026-03-09 10:50:47 +0100
commit19a117889c2db6b817af9458c04c04f324162e75 (patch)
treefbbd0d01c5bf40be90cec88e1d02c6a3c529a2f5 /src/zenserver
parentzenstore bug-fixes from static analysis pass (#815) (diff)
downloadzen-19a117889c2db6b817af9458c04c04f324162e75.tar.xz
zen-19a117889c2db6b817af9458c04c04f324162e75.zip
Eliminate spdlog dependency (#773)
Removes the vendored spdlog library (~12,000 lines) and replaces it with a purpose-built logging system in zencore (~1,800 lines). The new implementation provides the same functionality with fewer abstractions, no shared_ptr overhead, and full control over the logging pipeline. ### What changed **New logging core in zencore/logging/:** - LogMessage, Formatter, Sink, Logger, Registry - core abstractions matching spdlog's model but simplified - AnsiColorStdoutSink - ANSI color console output (replaces spdlog stdout_color_sink) - MsvcSink - OutputDebugString on Windows (replaces spdlog msvc_sink) - AsyncSink - async logging via BlockingQueue worker thread (replaces spdlog async_logger) - NullSink, MessageOnlyFormatter - utility types - Thread-safe timestamp caching in formatters using RwLock **Moved to zenutil/logging/:** - FullFormatter - full log formatting with timestamp, logger name, level, source location, multiline alignment - JsonFormatter - structured JSON log output - RotatingFileSink - rotating file sink with atomic size tracking **API changes:** - Log levels are now an enum (LogLevel) instead of int, eliminating the zen::logging::level namespace - LoggerRef no longer wraps shared_ptr - it holds a raw pointer with the registry owning lifetime - Logger error handler is wired through Registry and propagated to all loggers on registration - Logger::Log() now populates ThreadId on every message **Cleanup:** - Deleted thirdparty/spdlog/ entirely (110+ files) - Deleted full_test_formatter (was ~80% duplicate of FullFormatter) - Renamed snake_case classes to PascalCase (full_formatter -> FullFormatter, json_formatter -> JsonFormatter, sentry_sink -> SentrySink) - Removed spdlog from xmake dependency graph ### Build / test impact - zencore no longer depends on spdlog - zenutil and zenvfs xmake.lua updated to drop spdlog dep - zentelemetry xmake.lua updated to drop spdlog dep - All existing tests pass, no test changes required beyond formatter class renames
Diffstat (limited to 'src/zenserver')
-rw-r--r--src/zenserver/diag/diagsvcs.cpp6
-rw-r--r--src/zenserver/diag/logging.cpp51
-rw-r--r--src/zenserver/diag/otlphttp.cpp4
-rw-r--r--src/zenserver/diag/otlphttp.h15
-rw-r--r--src/zenserver/main.cpp2
-rw-r--r--src/zenserver/storage/admin/admin.cpp6
6 files changed, 38 insertions, 46 deletions
diff --git a/src/zenserver/diag/diagsvcs.cpp b/src/zenserver/diag/diagsvcs.cpp
index d8d53b0e3..5fa81ff9f 100644
--- a/src/zenserver/diag/diagsvcs.cpp
+++ b/src/zenserver/diag/diagsvcs.cpp
@@ -12,9 +12,7 @@
#include <fstream>
#include <sstream>
-ZEN_THIRD_PARTY_INCLUDES_START
-#include <spdlog/logger.h>
-ZEN_THIRD_PARTY_INCLUDES_END
+#include <zencore/logging/logger.h>
namespace zen {
@@ -64,7 +62,7 @@ HttpHealthService::HttpHealthService()
[this](HttpRouterRequest& RoutedReq) {
HttpServerRequest& HttpReq = RoutedReq.ServerRequest();
- zen::Log().SpdLogger->flush();
+ zen::Log().Flush();
std::filesystem::path Path = [&] {
RwLock::SharedLockScope _(m_InfoLock);
diff --git a/src/zenserver/diag/logging.cpp b/src/zenserver/diag/logging.cpp
index 75a8efc09..178c3d3b5 100644
--- a/src/zenserver/diag/logging.cpp
+++ b/src/zenserver/diag/logging.cpp
@@ -6,6 +6,8 @@
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
+#include <zencore/logging/logger.h>
+#include <zencore/logging/registry.h>
#include <zencore/memory/llm.h>
#include <zencore/session.h>
#include <zencore/string.h>
@@ -14,10 +16,6 @@
#include "otlphttp.h"
-ZEN_THIRD_PARTY_INCLUDES_START
-#include <spdlog/spdlog.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-
namespace zen {
void
@@ -43,13 +41,12 @@ InitializeServerLogging(const ZenServerConfig& InOptions, bool WithCacheService)
std::filesystem::path HttpLogPath = InOptions.DataDir / "logs" / "http.log";
zen::CreateDirectories(HttpLogPath.parent_path());
- auto HttpSink = std::make_shared<zen::logging::RotatingFileSink>(HttpLogPath,
- /* max size */ 128 * 1024 * 1024,
- /* max files */ 16,
- /* rotate on open */ true);
- auto HttpLogger = std::make_shared<spdlog::logger>("http_requests", HttpSink);
- spdlog::apply_logger_env_levels(HttpLogger);
- spdlog::register_logger(HttpLogger);
+ logging::SinkPtr HttpSink(new zen::logging::RotatingFileSink(HttpLogPath,
+ /* max size */ 128 * 1024 * 1024,
+ /* max files */ 16,
+ /* rotate on open */ true));
+ Ref<logging::Logger> HttpLogger(new logging::Logger("http_requests", std::vector<logging::SinkPtr>{HttpSink}));
+ logging::Registry::Instance().Register(HttpLogger);
if (WithCacheService)
{
@@ -57,33 +54,30 @@ InitializeServerLogging(const ZenServerConfig& InOptions, bool WithCacheService)
std::filesystem::path CacheLogPath = InOptions.DataDir / "logs" / "z$.log";
zen::CreateDirectories(CacheLogPath.parent_path());
- auto CacheSink = std::make_shared<zen::logging::RotatingFileSink>(CacheLogPath,
- /* max size */ 128 * 1024 * 1024,
- /* max files */ 16,
- /* rotate on open */ false);
- auto CacheLogger = std::make_shared<spdlog::logger>("z$", CacheSink);
- spdlog::apply_logger_env_levels(CacheLogger);
- spdlog::register_logger(CacheLogger);
+ logging::SinkPtr CacheSink(new zen::logging::RotatingFileSink(CacheLogPath,
+ /* max size */ 128 * 1024 * 1024,
+ /* max files */ 16,
+ /* rotate on open */ false));
+ Ref<logging::Logger> CacheLogger(new logging::Logger("z$", std::vector<logging::SinkPtr>{CacheSink}));
+ logging::Registry::Instance().Register(CacheLogger);
// Jupiter - only log upstream HTTP traffic to file
- auto JupiterLogger = std::make_shared<spdlog::logger>("jupiter", FileSink);
- spdlog::apply_logger_env_levels(JupiterLogger);
- spdlog::register_logger(JupiterLogger);
+ Ref<logging::Logger> JupiterLogger(new logging::Logger("jupiter", std::vector<logging::SinkPtr>{FileSink}));
+ logging::Registry::Instance().Register(JupiterLogger);
// Zen - only log upstream HTTP traffic to file
- auto ZenClientLogger = std::make_shared<spdlog::logger>("zenclient", FileSink);
- spdlog::apply_logger_env_levels(ZenClientLogger);
- spdlog::register_logger(ZenClientLogger);
+ Ref<logging::Logger> ZenClientLogger(new logging::Logger("zenclient", std::vector<logging::SinkPtr>{FileSink}));
+ logging::Registry::Instance().Register(ZenClientLogger);
}
#if ZEN_WITH_OTEL
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.LoggingConfig.OtelEndpointUri);
- zen::logging::Default().SpdLogger->sinks().push_back(std::move(OtelSink));
+ logging::SinkPtr OtelSink(new zen::logging::OtelHttpProtobufSink(InOptions.LoggingConfig.OtelEndpointUri));
+ zen::logging::Default()->AddSink(std::move(OtelSink));
}
#endif
@@ -91,9 +85,10 @@ InitializeServerLogging(const ZenServerConfig& InOptions, bool WithCacheService)
const zen::Oid ServerSessionId = zen::GetSessionId();
- spdlog::apply_all([&](auto Logger) {
+ static constinit logging::LogPoint SessionIdPoint{{}, logging::Info, "server session id: {}"};
+ logging::Registry::Instance().ApplyAll([&](auto Logger) {
ZEN_MEMSCOPE(ELLMTag::Logging);
- Logger->info("server session id: {}", ServerSessionId);
+ Logger->Log(SessionIdPoint, fmt::make_format_args(ServerSessionId));
});
}
diff --git a/src/zenserver/diag/otlphttp.cpp b/src/zenserver/diag/otlphttp.cpp
index d62ccccb6..1434c9331 100644
--- a/src/zenserver/diag/otlphttp.cpp
+++ b/src/zenserver/diag/otlphttp.cpp
@@ -53,7 +53,7 @@ OtelHttpProtobufSink::TraceRecorder::RecordSpans(zen::otel::TraceId Trace, std::
}
void
-OtelHttpProtobufSink::log(const spdlog::details::log_msg& Msg)
+OtelHttpProtobufSink::Log(const LogMessage& Msg)
{
{
std::string Data = m_Encoder.FormatOtelProtobuf(Msg);
@@ -74,7 +74,7 @@ OtelHttpProtobufSink::log(const spdlog::details::log_msg& Msg)
}
}
void
-OtelHttpProtobufSink::flush()
+OtelHttpProtobufSink::Flush()
{
}
diff --git a/src/zenserver/diag/otlphttp.h b/src/zenserver/diag/otlphttp.h
index 2281bdcc0..8254af04d 100644
--- a/src/zenserver/diag/otlphttp.h
+++ b/src/zenserver/diag/otlphttp.h
@@ -3,7 +3,7 @@
#pragma once
-#include <spdlog/sinks/sink.h>
+#include <zencore/logging/sink.h>
#include <zencore/zencore.h>
#include <zenhttp/httpclient.h>
#include <zentelemetry/otlpencoder.h>
@@ -14,12 +14,12 @@
namespace zen::logging {
/**
- * OTLP/HTTP sink for spdlog
+ * OTLP/HTTP sink for logging
*
* Sends log messages and traces to an OpenTelemetry collector via OTLP over HTTP
*/
-class OtelHttpProtobufSink : public spdlog::sinks::sink
+class OtelHttpProtobufSink : public Sink
{
public:
// Note that this URI should be the base URI of the OTLP HTTP endpoint, e.g.
@@ -31,10 +31,9 @@ public:
OtelHttpProtobufSink& operator=(const OtelHttpProtobufSink&) = delete;
private:
- virtual void log(const spdlog::details::log_msg& Msg) override;
- virtual void flush() override;
- virtual void set_pattern(const std::string& pattern) override { ZEN_UNUSED(pattern); }
- virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override { ZEN_UNUSED(sink_formatter); }
+ virtual void Log(const LogMessage& Msg) override;
+ virtual void Flush() override;
+ virtual void SetFormatter(std::unique_ptr<Formatter>) override {}
void RecordSpans(zen::otel::TraceId Trace, std::span<const zen::otel::Span*> Spans);
@@ -61,4 +60,4 @@ private:
} // namespace zen::logging
-#endif \ No newline at end of file
+#endif
diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp
index c764cbde6..09ecc48e5 100644
--- a/src/zenserver/main.cpp
+++ b/src/zenserver/main.cpp
@@ -246,7 +246,7 @@ test_main(int argc, char** argv)
# endif // ZEN_PLATFORM_WINDOWS
zen::logging::InitializeLogging();
- zen::logging::SetLogLevel(zen::logging::level::Debug);
+ zen::logging::SetLogLevel(zen::logging::Debug);
zen::MaximizeOpenFileCount();
diff --git a/src/zenserver/storage/admin/admin.cpp b/src/zenserver/storage/admin/admin.cpp
index 19155e02b..c9f999c69 100644
--- a/src/zenserver/storage/admin/admin.cpp
+++ b/src/zenserver/storage/admin/admin.cpp
@@ -716,7 +716,7 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler,
"logs",
[this](HttpRouterRequest& Req) {
CbObjectWriter Obj;
- auto LogLevel = logging::level::ToStringView(logging::GetLogLevel());
+ auto LogLevel = logging::ToStringView(logging::GetLogLevel());
Obj.AddString("loglevel", std::string_view(LogLevel.data(), LogLevel.size()));
Obj.AddString("Logfile", PathToUtf8(m_LogPaths.AbsLogPath));
Obj.BeginObject("cache");
@@ -767,8 +767,8 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler,
}
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);
+ logging::LogLevel NewLevel = logging::ParseLogLevelString(Param);
+ std::string_view LogLevel = logging::ToStringView(NewLevel);
if (LogLevel != Param)
{
return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest,