aboutsummaryrefslogtreecommitdiff
path: root/src/zencore
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore')
-rw-r--r--src/zencore/include/zencore/fmtutils.h23
-rw-r--r--src/zencore/include/zencore/logbase.h96
-rw-r--r--src/zencore/include/zencore/logging.h269
-rw-r--r--src/zencore/include/zencore/string.h22
-rw-r--r--src/zencore/include/zencore/zencore.h2
-rw-r--r--src/zencore/logging.cpp241
-rw-r--r--src/zencore/testing.cpp4
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);
}
}