diff options
| author | Stefan Boberg <[email protected]> | 2023-11-06 20:36:30 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-06 20:36:30 +0100 |
| commit | 07f288d6e119fc6bb524fb634bc9094109a2ab05 (patch) | |
| tree | 8531bd38d0d8c3567ba3d0a5603f549faf99632b /src/zencore/logging.cpp | |
| parent | gc v2 tests (#512) (diff) | |
| download | zen-07f288d6e119fc6bb524fb634bc9094109a2ab05.tar.xz zen-07f288d6e119fc6bb524fb634bc9094109a2ab05.zip | |
spdlog implementation hiding (#498)
this change aims to hide logging internals from client code, in order to make it easier to extend and take more control over the logging process in the future.
As a bonus side effect, the generated code is much tighter (net delta around 2.5% on the resulting executable which includes lots of thirdparty code) and should take less time to compile and link.
Client usage via macros is pretty much unchanged. The main exposure client code had to spdlog internals before was the use of custom loggers per subsystem, where it would be common to have `spdlog::logger` references to keep a reference to a logger within a class. This is now replaced by `zen::LoggerRef` which currently simply encapsulates an actual `spdlog::logger` instance, but this is intended to be an implementation detail which will change in the future.
The way the change works is that we now handle any formatting of log messages in the zencore logging subsystem instead of relying on `spdlog` to manage this. We use the `fmt` library to do the formatting which means the client usage is identical to using `spdlog`. The formatted message is then forwarded onto any sinks etc which are still implememted via `spdlog`.
Diffstat (limited to 'src/zencore/logging.cpp')
| -rw-r--r-- | src/zencore/logging.cpp | 241 |
1 files changed, 216 insertions, 25 deletions
diff --git a/src/zencore/logging.cpp b/src/zencore/logging.cpp index c366df812..0d34372a9 100644 --- a/src/zencore/logging.cpp +++ b/src/zencore/logging.cpp @@ -7,39 +7,239 @@ #include <spdlog/sinks/null_sink.h> #include <spdlog/sinks/stdout_color_sinks.h> +#include <spdlog/spdlog.h> + +#if ZEN_PLATFORM_WINDOWS +# pragma section(".zlog$a", read) +# pragma section(".zlog$f", read) +# pragma section(".zlog$m", read) +# pragma section(".zlog$s", read) +# pragma section(".zlog$z", read) +#endif namespace zen { // We shadow the underlying spdlog default logger, in order to avoid a bunch of overhead -spdlog::logger* TheDefaultLogger; +LoggerRef TheDefaultLogger; } // namespace zen namespace zen::logging { -spdlog::logger& +using MemoryBuffer_t = fmt::basic_memory_buffer<char, 250>; + +struct LoggingContext +{ + inline LoggingContext(); + inline ~LoggingContext(); + + zen::logging::MemoryBuffer_t MessageBuffer; + + inline std::string_view Message() const { return std::string_view(MessageBuffer.data(), MessageBuffer.size()); } +}; + +LoggingContext::LoggingContext() +{ +} + +LoggingContext::~LoggingContext() +{ +} + +static inline bool +IsErrorLevel(int LogLevel) +{ + return (LogLevel == zen::logging::level::Err || LogLevel == zen::logging::level::Critical); +}; + +static_assert(sizeof(spdlog::source_loc) == sizeof(SourceLocation)); +static_assert(offsetof(spdlog::source_loc, filename) == offsetof(SourceLocation, filename)); +static_assert(offsetof(spdlog::source_loc, line) == offsetof(SourceLocation, line)); +static_assert(offsetof(spdlog::source_loc, funcname) == offsetof(SourceLocation, funcname)); + +void +EmitLogMessage(LoggerRef& Logger, int LogLevel, const std::string_view Message) +{ + const spdlog::level::level_enum InLevel = (spdlog::level::level_enum)LogLevel; + Logger.SpdLogger->log(InLevel, Message); + if (IsErrorLevel(LogLevel)) + { + if (LoggerRef ErrLogger = zen::logging::ErrorLog()) + { + ErrLogger.SpdLogger->log(InLevel, Message); + } + } +} + +void +EmitLogMessage(LoggerRef& Logger, int LogLevel, std::string_view Format, fmt::format_args Args) +{ + zen::logging::LoggingContext LogCtx; + fmt::vformat_to(fmt::appender(LogCtx.MessageBuffer), Format, Args); + zen::logging::EmitLogMessage(Logger, LogLevel, LogCtx.Message()); +} + +void +EmitLogMessage(LoggerRef& Logger, const SourceLocation& InLocation, int LogLevel, const std::string_view Message) +{ + const spdlog::source_loc& Location = *reinterpret_cast<const spdlog::source_loc*>(&InLocation); + const spdlog::level::level_enum InLevel = (spdlog::level::level_enum)LogLevel; + Logger.SpdLogger->log(Location, InLevel, Message); + if (IsErrorLevel(LogLevel)) + { + if (LoggerRef ErrLogger = zen::logging::ErrorLog()) + { + ErrLogger.SpdLogger->log(Location, InLevel, Message); + } + } +} + +void +EmitLogMessage(LoggerRef& Logger, const SourceLocation& InLocation, int LogLevel, std::string_view Format, fmt::format_args Args) +{ + zen::logging::LoggingContext LogCtx; + fmt::vformat_to(fmt::appender(LogCtx.MessageBuffer), Format, Args); + zen::logging::EmitLogMessage(Logger, InLocation, LogLevel, LogCtx.Message()); +} + +void +EmitConsoleLogMessage(int LogLevel, const std::string_view Message) +{ + const spdlog::level::level_enum InLevel = (spdlog::level::level_enum)LogLevel; + ConsoleLog().SpdLogger->log(InLevel, Message); +} + +void +EmitConsoleLogMessage(int LogLevel, std::string_view Format, fmt::format_args Args) +{ + zen::logging::LoggingContext LogCtx; + fmt::vformat_to(fmt::appender(LogCtx.MessageBuffer), Format, Args); + zen::logging::EmitConsoleLogMessage(LogLevel, LogCtx.Message()); +} + +} // namespace zen::logging + +namespace zen::logging::level { + +spdlog::level::level_enum +to_spdlog_level(LogLevel NewLogLevel) +{ + return static_cast<spdlog::level::level_enum>((int)NewLogLevel); +} + +LogLevel +to_logging_level(spdlog::level::level_enum NewLogLevel) +{ + return static_cast<LogLevel>((int)NewLogLevel); +} + +constinit std::string_view LevelNames[] = {ZEN_LEVEL_NAME_TRACE, + ZEN_LEVEL_NAME_DEBUG, + ZEN_LEVEL_NAME_INFO, + ZEN_LEVEL_NAME_WARNING, + ZEN_LEVEL_NAME_ERROR, + ZEN_LEVEL_NAME_CRITICAL, + ZEN_LEVEL_NAME_OFF}; + +level::LogLevel +ParseLogLevelString(std::string_view Name) +{ + for (int Level = 0; Level < level::LogLevelCount; ++Level) + { + if (LevelNames[Level] == Name) + return static_cast<level::LogLevel>(Level); + } + + if (Name == "warn") + { + return level::Warn; + } + + if (Name == "err") + { + return level::Err; + } + + return level::Off; +} + +std::string_view +ToStringView(level::LogLevel Level) +{ + if (int(Level) < level::LogLevelCount) + { + return LevelNames[int(Level)]; + } + + return "None"; +} + +} // namespace zen::logging::level + +namespace zen::logging { + +void +SetLogLevel(level::LogLevel NewLogLevel) +{ + spdlog::set_level(to_spdlog_level(NewLogLevel)); +} + +level::LogLevel +GetLogLevel() +{ + return level::to_logging_level(spdlog::get_level()); +} + +LoggerRef Default() { ZEN_ASSERT(TheDefaultLogger); - return *TheDefaultLogger; + return TheDefaultLogger; } void -SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger) +SetDefault(std::string_view NewDefaultLoggerId) { + auto NewDefaultLogger = spdlog::get(std::string(NewDefaultLoggerId)); ZEN_ASSERT(NewDefaultLogger); + spdlog::set_default_logger(NewDefaultLogger); - TheDefaultLogger = spdlog::default_logger_raw(); + TheDefaultLogger = LoggerRef(*NewDefaultLogger); +} + +LoggerRef TheErrorLogger; + +LoggerRef +ErrorLog() +{ + return TheErrorLogger; } -spdlog::logger& +void +SetErrorLog(std::string_view NewErrorLoggerId) +{ + if (NewErrorLoggerId.empty()) + { + TheErrorLogger = {}; + } + else + { + auto NewErrorLogger = spdlog::get(std::string(NewErrorLoggerId)); + + ZEN_ASSERT(NewErrorLogger); + + TheErrorLogger = LoggerRef(*NewErrorLogger.get()); + } +} + +LoggerRef Get(std::string_view Name) { std::shared_ptr<spdlog::logger> Logger = spdlog::get(std::string(Name)); if (!Logger) { - Logger = Default().clone(std::string(Name)); + Logger = Default().SpdLogger->clone(std::string(Name)); spdlog::register_logger(Logger); } @@ -55,7 +255,7 @@ SuppressConsoleLog() ConLogger = spdlog::null_logger_mt("console"); } -spdlog::logger& +LoggerRef ConsoleLog() { std::call_once(ConsoleInitFlag, [&] { @@ -70,25 +270,10 @@ ConsoleLog() return *ConLogger; } -std::shared_ptr<spdlog::logger> TheErrorLogger; - -spdlog::logger* -ErrorLog() -{ - // This may return nullptr - return TheErrorLogger.get(); -} - -void -SetErrorLog(std::shared_ptr<spdlog::logger>&& NewErrorLogger) -{ - TheErrorLogger = std::move(NewErrorLogger); -} - void InitializeLogging() { - TheDefaultLogger = spdlog::default_logger_raw(); + TheDefaultLogger = *spdlog::default_logger_raw(); } void @@ -96,7 +281,7 @@ ShutdownLogging() { spdlog::drop_all(); spdlog::shutdown(); - TheDefaultLogger = nullptr; + TheDefaultLogger = {}; } bool @@ -130,6 +315,12 @@ EnableVTMode() namespace zen { +bool +LoggerRef::ShouldLog(int Level) const +{ + return SpdLogger->should_log(static_cast<spdlog::level::level_enum>(Level)); +} + thread_local ScopedActivityBase* t_ScopeStack = nullptr; ScopedActivityBase* |