diff options
Diffstat (limited to 'src/zencore')
| -rw-r--r-- | src/zencore/include/zencore/fmtutils.h | 23 | ||||
| -rw-r--r-- | src/zencore/include/zencore/logbase.h | 96 | ||||
| -rw-r--r-- | src/zencore/include/zencore/logging.h | 269 | ||||
| -rw-r--r-- | src/zencore/include/zencore/string.h | 22 | ||||
| -rw-r--r-- | src/zencore/include/zencore/zencore.h | 2 | ||||
| -rw-r--r-- | src/zencore/logging.cpp | 241 | ||||
| -rw-r--r-- | src/zencore/testing.cpp | 4 |
7 files changed, 488 insertions, 169 deletions
diff --git a/src/zencore/include/zencore/fmtutils.h b/src/zencore/include/zencore/fmtutils.h index 3d29625be..9c5bdae66 100644 --- a/src/zencore/include/zencore/fmtutils.h +++ b/src/zencore/include/zencore/fmtutils.h @@ -16,6 +16,26 @@ ZEN_THIRD_PARTY_INCLUDES_END // Custom formatting for some zencore types +template<typename T> +requires DerivedFrom<T, zen::StringBuilderBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> +{ + auto format(const zen::StringBuilderBase& a, format_context& ctx) const + { + return fmt::formatter<std::string_view>::format(a.ToView(), ctx); + } +}; + +template<typename T> +requires DerivedFrom<T, zen::NiceBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> +{ + auto format(const zen::NiceBase& a, format_context& ctx) const + { + return fmt::formatter<std::string_view>::format(std::string_view(a), ctx); + } +}; + template<> struct fmt::formatter<zen::IoHash> : formatter<string_view> { @@ -74,7 +94,8 @@ struct fmt::formatter<std::filesystem::path> : formatter<string_view> }; template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::PathBuilderBase, T>::value, char>> : fmt::formatter<std::string_view> +requires DerivedFrom<T, zen::PathBuilderBase> +struct fmt::formatter<T> : fmt::formatter<std::string_view> { auto format(const zen::PathBuilderBase& a, format_context& ctx) const { diff --git a/src/zencore/include/zencore/logbase.h b/src/zencore/include/zencore/logbase.h new file mode 100644 index 000000000..ad873aa51 --- /dev/null +++ b/src/zencore/include/zencore/logbase.h @@ -0,0 +1,96 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <string_view> + +#define ZEN_LOG_LEVEL_TRACE 0 +#define ZEN_LOG_LEVEL_DEBUG 1 +#define ZEN_LOG_LEVEL_INFO 2 +#define ZEN_LOG_LEVEL_WARN 3 +#define ZEN_LOG_LEVEL_ERROR 4 +#define ZEN_LOG_LEVEL_CRITICAL 5 +#define ZEN_LOG_LEVEL_OFF 6 + +#define ZEN_LEVEL_NAME_TRACE std::string_view("trace", 5) +#define ZEN_LEVEL_NAME_DEBUG std::string_view("debug", 5) +#define ZEN_LEVEL_NAME_INFO std::string_view("info", 4) +#define ZEN_LEVEL_NAME_WARNING std::string_view("warning", 7) +#define ZEN_LEVEL_NAME_ERROR std::string_view("error", 5) +#define ZEN_LEVEL_NAME_CRITICAL std::string_view("critical", 8) +#define ZEN_LEVEL_NAME_OFF std::string_view("off", 3) + +namespace zen::logging::level { + +enum LogLevel : int +{ + Trace = ZEN_LOG_LEVEL_TRACE, + Debug = ZEN_LOG_LEVEL_DEBUG, + Info = ZEN_LOG_LEVEL_INFO, + Warn = ZEN_LOG_LEVEL_WARN, + Err = ZEN_LOG_LEVEL_ERROR, + Critical = ZEN_LOG_LEVEL_CRITICAL, + Off = ZEN_LOG_LEVEL_OFF, + LogLevelCount +}; + +LogLevel ParseLogLevelString(std::string_view String); +std::string_view ToStringView(LogLevel Level); + +} // namespace zen::logging::level + +namespace zen::logging { + +void SetLogLevel(level::LogLevel NewLogLevel); +level::LogLevel GetLogLevel(); + +} // namespace zen::logging + +namespace spdlog { +class logger; +} + +namespace zen::logging { + +struct SourceLocation +{ + constexpr SourceLocation() = default; + constexpr SourceLocation(const char* filename_in, int line_in, const char* funcname_in) + : filename(filename_in) + , line(line_in) + , funcname(funcname_in) + { + } + + constexpr bool empty() const noexcept { return line == 0; } + + // IMPORTANT NOTE: the layout of this class must match the spdlog::source_loc class + // since we currently pass a pointer to it into spdlog after casting it to + // spdlog::source_loc* + // + // This is intended to be an intermediate state, before we (probably) transition off + // spdlog entirely + + const char* filename{nullptr}; + int line{0}; + const char* funcname{nullptr}; +}; + +} // namespace zen::logging + +namespace zen { + +struct LoggerRef +{ + LoggerRef() = default; + LoggerRef(spdlog::logger& InLogger) : SpdLogger(&InLogger) {} + + LoggerRef Logger() { return *this; } + + bool ShouldLog(int Level) const; + inline operator bool() const { return SpdLogger != nullptr; } + + spdlog::logger* SpdLogger = nullptr; +}; + +} // namespace zen diff --git a/src/zencore/include/zencore/logging.h b/src/zencore/include/zencore/logging.h index c0d966475..e3eb524e9 100644 --- a/src/zencore/include/zencore/logging.h +++ b/src/zencore/include/zencore/logging.h @@ -2,138 +2,179 @@ #pragma once +#include <zencore/logbase.h> #include <zencore/zencore.h> -ZEN_THIRD_PARTY_INCLUDES_START -#include <spdlog/spdlog.h> -#undef GetObject -ZEN_THIRD_PARTY_INCLUDES_END - -#include <string_view> +#include <fmt/args.h> + +#if ZEN_PLATFORM_WINDOWS +# define ZEN_LOG_SECTION(Id) ZEN_DATA_SECTION(Id) +# pragma section(".zlog$f", read) +# pragma section(".zlog$l", read) +# pragma section(".zlog$m", read) +# pragma section(".zlog$s", read) +# define ZEN_DECLARE_FUNCTION static constinit ZEN_LOG_SECTION(".zlog$f") char FuncName[] = __FUNCTION__; +# define ZEN_LOG_FUNCNAME FuncName +#else +# define ZEN_LOG_SECTION(Id) +# define ZEN_DECLARE_FUNCTION +# define ZEN_LOG_FUNCNAME static_cast<const char*>(__func__) +#endif namespace zen::logging { -spdlog::logger& Default(); -void SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger); -spdlog::logger& ConsoleLog(); -void SuppressConsoleLog(); -spdlog::logger& Get(std::string_view Name); -spdlog::logger* ErrorLog(); -void SetErrorLog(std::shared_ptr<spdlog::logger>&& NewErrorLogger); - void InitializeLogging(); void ShutdownLogging(); - bool EnableVTMode(); +LoggerRef Default(); +void SetDefault(std::string_view NewDefaultLoggerId); +LoggerRef ConsoleLog(); +void SuppressConsoleLog(); +LoggerRef ErrorLog(); +void SetErrorLog(std::string_view LoggerId); +LoggerRef Get(std::string_view Name); + +struct LogCategory +{ + inline LogCategory(std::string_view InCategory) : CategoryName(InCategory) {} + + inline zen::LoggerRef Logger() + { + if (LoggerRef) + { + return LoggerRef; + } + + LoggerRef = zen::logging::Get(CategoryName); + return LoggerRef; + } + + std::string CategoryName; + zen::LoggerRef LoggerRef; +}; + +void EmitConsoleLogMessage(int LogLevel, std::string_view Message); +void EmitConsoleLogMessage(int LogLevel, std::string_view Format, fmt::format_args Args); +void EmitLogMessage(LoggerRef& Logger, int LogLevel, std::string_view Message); +void EmitLogMessage(LoggerRef& Logger, const SourceLocation& Location, int LogLevel, std::string_view Message); +void EmitLogMessage(LoggerRef& Logger, int LogLevel, std::string_view Format, fmt::format_args Args); +void EmitLogMessage(LoggerRef& Logger, const SourceLocation& Location, int LogLevel, std::string_view Format, fmt::format_args Args); + } // namespace zen::logging namespace zen { -extern spdlog::logger* TheDefaultLogger; -inline spdlog::logger& +extern LoggerRef TheDefaultLogger; + +inline LoggerRef Log() { - if (TheDefaultLogger == nullptr) + if (TheDefaultLogger) { - return zen::logging::ConsoleLog(); + return TheDefaultLogger; } - return *TheDefaultLogger; + return zen::logging::ConsoleLog(); } using logging::ConsoleLog; using logging::ErrorLog; + } // namespace zen using zen::ConsoleLog; using zen::ErrorLog; using zen::Log; -struct LogCategory -{ - LogCategory(std::string_view InCategory) : Category(InCategory) {} - - spdlog::logger& Logger() - { - static spdlog::logger& Inst = zen::logging::Get(Category); - return Inst; - } - - std::string Category; -}; - inline consteval bool -LogIsErrorLevel(int level) +LogIsErrorLevel(int LogLevel) { - return (level == spdlog::level::err || level == spdlog::level::critical); + return (LogLevel == zen::logging::level::Err || LogLevel == zen::logging::level::Critical); }; -#define ZEN_LOG_WITH_LOCATION(logger, loc, level, fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - if (logger.should_log(level)) \ - { \ - logger.log(loc, level, fmtstr, ##__VA_ARGS__); \ - if (LogIsErrorLevel(level)) \ - { \ - if (auto ErrLogger = zen::logging::ErrorLog(); ErrLogger != nullptr) \ - { \ - ErrLogger->log(loc, level, fmtstr, ##__VA_ARGS__); \ - } \ - } \ - } \ +#if ZEN_BUILD_DEBUG +# define ZEN_CHECK_FORMAT_STRING(fmtstr, ...) \ + while (false) \ + { \ + (void)fmt::format(fmtstr, ##__VA_ARGS__); \ + } +#else +# define ZEN_CHECK_FORMAT_STRING(fmtstr, ...) \ + while (false) \ + { \ + } +#endif + +#define ZEN_LOG_WITH_LOCATION(InLogger, InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + ZEN_DECLARE_FUNCTION \ + static constinit ZEN_LOG_SECTION(".zlog$s") char FileName[] = __FILE__; \ + static constinit ZEN_LOG_SECTION(".zlog$m") char FormatString[] = fmtstr; \ + static constinit ZEN_LOG_SECTION(".zlog$l") zen::logging::SourceLocation Location{FileName, __LINE__, ZEN_LOG_FUNCNAME}; \ + zen::LoggerRef Logger = InLogger; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + if (Logger.ShouldLog(InLevel)) \ + { \ + zen::logging::EmitLogMessage(Logger, \ + Location, \ + InLevel, \ + std::string_view(FormatString, sizeof FormatString - 1), \ + fmt::make_format_args(__VA_ARGS__)); \ + } \ } while (false); -#define ZEN_LOG(logger, level, fmtstr, ...) ZEN_LOG_WITH_LOCATION(logger, spdlog::source_loc{}, level, fmtstr, ##__VA_ARGS__) - -#define ZEN_DEFINE_LOG_CATEGORY_STATIC(Category, Name) \ - static struct LogCategory##Category : public LogCategory \ - { \ - LogCategory##Category() : LogCategory(Name) {} \ - } Category; - -#define ZEN_LOG_TRACE(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::trace, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_DEBUG(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::debug, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_INFO(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::info, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_WARN(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), spdlog::level::warn, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_LOG_ERROR(Category, fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Category.Logger(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::err, \ - fmtstr##sv, \ - ##__VA_ARGS__) - -#define ZEN_LOG_CRITICAL(Category, fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Category.Logger(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr##sv, \ - ##__VA_ARGS__) - - // Helper macros for logging - -#define ZEN_TRACE(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::trace, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_DEBUG(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::debug, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_INFO(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::info, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_WARN(fmtstr, ...) ZEN_LOG(Log(), spdlog::level::warn, fmtstr##sv, ##__VA_ARGS__) -#define ZEN_ERROR(fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Log(), spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), spdlog::level::err, fmtstr##sv, ##__VA_ARGS__) - -#define ZEN_CRITICAL(fmtstr, ...) \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr##sv, \ - ##__VA_ARGS__) - -#define ZEN_CONSOLE(fmtstr, ...) \ - do \ - { \ - using namespace std::literals; \ - ConsoleLog().info(fmtstr##sv, ##__VA_ARGS__); \ +#define ZEN_LOG(InLogger, InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + static constinit ZEN_LOG_SECTION(".zlog$m") char FormatString[] = fmtstr; \ + zen::LoggerRef Logger = InLogger; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + if (Logger.ShouldLog(InLevel)) \ + { \ + zen::logging::EmitLogMessage(Logger, \ + InLevel, \ + std::string_view(FormatString, sizeof FormatString - 1), \ + fmt::make_format_args(__VA_ARGS__)); \ + } \ + } while (false); + +#define ZEN_DEFINE_LOG_CATEGORY_STATIC(Category, Name) \ + static zen::logging::LogCategory Category { Name } + +#define ZEN_LOG_TRACE(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_DEBUG(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_INFO(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_WARN(Category, fmtstr, ...) ZEN_LOG(Category.Logger(), zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_ERROR(Category, fmtstr, ...) ZEN_LOG_WITH_LOCATION(Category.Logger(), zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_LOG_CRITICAL(Category, fmtstr, ...) \ + ZEN_LOG_WITH_LOCATION(Category.Logger(), zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + +#define ZEN_TRACE(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_DEBUG(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_INFO(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_WARN(fmtstr, ...) ZEN_LOG(Log(), zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_ERROR(fmtstr, ...) ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_CRITICAL(fmtstr, ...) ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + +#define ZEN_CONSOLE_LOG(InLevel, fmtstr, ...) \ + do \ + { \ + using namespace std::literals; \ + ZEN_CHECK_FORMAT_STRING(fmtstr##sv, ##__VA_ARGS__); \ + zen::logging::EmitConsoleLogMessage(InLevel, fmtstr, fmt::make_format_args(__VA_ARGS__)); \ } while (false) +#define ZEN_CONSOLE(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_TRACE(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Trace, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_DEBUG(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Debug, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_INFO(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Info, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_WARN(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Warn, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_ERROR(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Err, fmtstr, ##__VA_ARGS__) +#define ZEN_CONSOLE_CRITICAL(fmtstr, ...) ZEN_CONSOLE_LOG(zen::logging::level::Critical, fmtstr, ##__VA_ARGS__) + ////////////////////////////////////////////////////////////////////////// namespace zen { @@ -187,30 +228,20 @@ std::string_view EmitActivitiesForLogging(StringBuilderBase& OutString); #define ZEN_LOG_SCOPE(...) ScopedLazyActivity $Activity##__LINE__([&](StringBuilderBase& Out) { Out << fmt::format(__VA_ARGS__); }) -#define ZEN_SCOPED_ERROR(fmtstr, ...) \ - do \ - { \ - ExtendableStringBuilder<256> ScopeString; \ - const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::err, \ - fmtstr "{}"sv, \ - ##__VA_ARGS__, \ - Scopes); \ +#define ZEN_SCOPED_ERROR(fmtstr, ...) \ + do \ + { \ + ExtendableStringBuilder<256> ScopeString; \ + const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ + ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Err, fmtstr "{}", ##__VA_ARGS__, Scopes); \ } while (false) -#define ZEN_SCOPED_CRITICAL(fmtstr, ...) \ - do \ - { \ - ExtendableStringBuilder<256> ScopeString; \ - const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ - ZEN_LOG_WITH_LOCATION(Log(), \ - spdlog::source_loc(__FILE__, __LINE__, SPDLOG_FUNCTION), \ - spdlog::level::critical, \ - fmtstr "{}"sv, \ - ##__VA_ARGS__, \ - Scopes); \ +#define ZEN_SCOPED_CRITICAL(fmtstr, ...) \ + do \ + { \ + ExtendableStringBuilder<256> ScopeString; \ + const std::string_view Scopes = EmitActivitiesForLogging(ScopeString); \ + ZEN_LOG_WITH_LOCATION(Log(), zen::logging::level::Critical, fmtstr "{}", ##__VA_ARGS__, Scopes); \ } while (false) ScopedActivityBase* GetThreadActivity(); diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index d0bd38acc..e3de2224c 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -17,10 +17,6 @@ #include <type_traits> -ZEN_THIRD_PARTY_INCLUDES_START -#include <fmt/format.h> -ZEN_THIRD_PARTY_INCLUDES_END - namespace zen { ////////////////////////////////////////////////////////////////////////// @@ -1141,21 +1137,3 @@ private: void string_forcelink(); // internal } // namespace zen - -template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::StringBuilderBase, T>::value, char>> : fmt::formatter<std::string_view> -{ - auto format(const zen::StringBuilderBase& a, format_context& ctx) const - { - return fmt::formatter<std::string_view>::format(a.ToView(), ctx); - } -}; - -template<typename T> -struct fmt::formatter<T, std::enable_if_t<std::is_base_of<zen::NiceBase, T>::value, char>> : fmt::formatter<std::string_view> -{ - auto format(const zen::NiceBase& a, format_context& ctx) const - { - return fmt::formatter<std::string_view>::format(std::string_view(a), ctx); - } -}; diff --git a/src/zencore/include/zencore/zencore.h b/src/zencore/include/zencore/zencore.h index 299fa2c31..562376c95 100644 --- a/src/zencore/include/zencore/zencore.h +++ b/src/zencore/include/zencore/zencore.h @@ -229,10 +229,12 @@ static_assert(sizeof(wchar_t) == 2, "wchar_t is expected to be two bytes in size #if ZEN_PLATFORM_WINDOWS // Tells the compiler to put the decorated function in a certain section (aka. segment) of the executable. # define ZEN_CODE_SECTION(Name) __declspec(code_seg(Name)) +# define ZEN_DATA_SECTION(Name) __declspec(allocate(Name)) # define ZEN_FORCENOINLINE __declspec(noinline) /* Force code to NOT be inline */ # define LINE_TERMINATOR_ANSI "\r\n" #else # define ZEN_CODE_SECTION(Name) +# define ZEN_DATA_SECTION(Name) # define ZEN_FORCENOINLINE # define LINE_TERMINATOR_ANSI "\n" #endif 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* diff --git a/src/zencore/testing.cpp b/src/zencore/testing.cpp index 6e1f55eda..54d89ded2 100644 --- a/src/zencore/testing.cpp +++ b/src/zencore/testing.cpp @@ -32,11 +32,11 @@ TestRunner::ApplyCommandLine(int argc, char const* const* argv) { if (argv[i] == "--debug"sv) { - spdlog::set_level(spdlog::level::debug); + zen::logging::SetLogLevel(zen::logging::level::Debug); } else if (argv[i] == "--verbose"sv) { - spdlog::set_level(spdlog::level::trace); + zen::logging::SetLogLevel(zen::logging::level::Trace); } } |