23#if defined(LK_PLATFORM_WINDOWS)
25#elif defined(LK_PLATFORM_LINUX)
26# include <spdlog/fmt/fmt.h>
31#if LK_LOG_USE_IOSTREAM
36#if defined(LK_PLATFORM_WINDOWS)
37# define LK_ASSERT_MESSAGE_BOX 1
38# define LK_ENGINE_CONSOLE_ENABLED 1
40# define LK_ASSERT_MESSAGE_BOX 0
41# define LK_ENGINE_CONSOLE_ENABLED 1
48#define SPDLOG_LEVEL_NAMES \
49 { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" }
51#include <spdlog/spdlog.h>
52#include <spdlog/fmt/ostr.h>
53#include <spdlog/fmt/fmt.h>
56#include <glm/gtx/string_cast.hpp>
58#include "LkEngine/Core/Assert.h"
61#include "LkEngine/Renderer/Color.h"
99 using LogLevelColorConfig = std::pair<ELogLevel, uint16_t>;
123 static void Initialize(std::string_view LogfileName =
"");
126 const std::string& Name,
127 const ELogLevel LogLevel = ELogLevel::Info,
128 const std::vector<LogLevelColorConfig>& LevelConfigs = {},
129 const Color::EColorCode MainColor = Color::EColorCode::Reset);
138 case ELoggerType::Core:
return Logger_Core;
139 case ELoggerType::Client:
return Logger_Client;
140 case ELoggerType::EditorConsole:
return Logger_EditorConsole;
141 case ELoggerType::TestRunner:
return Logger_TestRunner;
151 template<
typename... TArgs>
152 #if defined(LK_ENGINE_MSVC)
154 std::format_string<TArgs...> Format, TArgs&&... Args);
155 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
157 fmt::format_string<TArgs...> Format, TArgs&&... Args);
164 template<
typename... TArgs>
165 #if defined(LK_ENGINE_MSVC)
167 std::format_string<TArgs...> Format, TArgs&&... Args);
168 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
170 fmt::format_string<TArgs...> Format, TArgs&&... Args);
174 std::string_view Tag, std::string_view Message);
176 template<
typename... TArgs>
177 #if defined(LK_ENGINE_MSVC)
178 static void PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Prefix,
179 std::format_string<TArgs...> Message, TArgs&&... Args);
180 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
181 static void PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Prefix,
182 fmt::format_string<TArgs...> Message, TArgs&&... Args);
184 static void PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Prefix);
186 template<
typename... TArgs>
187 #if defined(LK_ENGINE_MSVC)
188 static void Print(std::format_string<TArgs...> Format, TArgs&&... Args)
189 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
190 static void Print(fmt::format_string<TArgs...> Format, TArgs&&... Args)
193 #if LK_LOG_USE_IOSTREAM
194 std::ostream_iterator<char> Out(std::cout);
195 std::format_to(Out, Format, std::forward<TArgs>(Args)...);
197 #if defined(LK_ENGINE_MSVC)
198 const std::string FormattedString = std::format(Format, std::forward<TArgs>(Args)...);
199 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
200 const std::string FormattedString = fmt::format(Format, std::forward<TArgs>(Args)...);
203 printf(
"%s", FormattedString.c_str());
208 template<
typename... TArgs>
209 #if defined(LK_ENGINE_MSVC)
210 static void PrintLn(std::format_string<TArgs...> Format, TArgs&&... Args)
211 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
212 static void PrintLn(fmt::format_string<TArgs...> Format, TArgs&&... Args)
215 #if LK_LOG_USE_IOSTREAM
216 std::ostream_iterator<char> Out(std::cout);
217 std::format_to(Out, Format, std::forward<TArgs>(Args)...);
220 #if defined(LK_ENGINE_MSVC)
221 const std::string FormattedString = std::format(Format, std::forward<TArgs>(Args)...);
222 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
223 const std::string FormattedString = fmt::format(Format, std::forward<TArgs>(Args)...);
225 printf(
"%s\n", FormattedString.c_str());
230 FORCEINLINE
static const char* LevelToString(
const ELogLevel Level)
234 case ELogLevel::Trace:
return "Trace";
235 case ELogLevel::Debug:
return "Debug";
236 case ELogLevel::Info:
return "Info";
237 case ELogLevel::Warning:
return "Warning";
238 case ELogLevel::Error:
return "Error";
239 case ELogLevel::Fatal:
return "Fatal";
242 LK_CORE_ASSERT(
false,
"Unknown log level: {}",
static_cast<int>(Level));
246 FORCEINLINE
static ELogLevel LevelFromString(std::string_view InString)
248 const std::string StrLower = StringUtils::ToLower(InString);
249 if (StrLower ==
"trace")
return ELogLevel::Trace;
250 else if (StrLower ==
"debug")
return ELogLevel::Debug;
251 else if (StrLower ==
"info")
return ELogLevel::Info;
252 else if (StrLower ==
"warning")
return ELogLevel::Warning;
253 else if (StrLower ==
"error")
return ELogLevel::Error;
254 else if (StrLower ==
"fatal")
return ELogLevel::Fatal;
256 LK_CORE_ASSERT(
false,
"LevelFromString failed for '{}' (lower: '{}')", InString, StrLower);
257 return ELogLevel::Info;
267 case ELogLevel::Trace:
return spdlog::level::trace;
268 case ELogLevel::Debug:
return spdlog::level::debug;
269 case ELogLevel::Info:
return spdlog::level::info;
270 case ELogLevel::Warning:
return spdlog::level::warn;
271 case ELogLevel::Error:
return spdlog::level::err;
272 case ELogLevel::Fatal:
return spdlog::level::critical;
275 LK_CORE_ASSERT(
false,
"ToSpdlogLevel error");
276 return spdlog::level::info;
279 template<
bool Safe = false>
280 FORCEINLINE
static std::string_view GetLoggerName(
const ELoggerType LoggerType)
286 case ELoggerType::Core:
return (Logger_Core ? Logger_Core->name() :
"");
287 case ELoggerType::Client:
return (Logger_Client ? Logger_Client->name() :
"");
288 case ELoggerType::EditorConsole:
return (Logger_EditorConsole ? Logger_EditorConsole->name() :
"");
289 case ELoggerType::TestRunner:
return (Logger_TestRunner ? Logger_TestRunner->name() :
"");
296 case ELoggerType::Core:
return Logger_Core->name();
297 case ELoggerType::Client:
return Logger_Client->name();
298 case ELoggerType::EditorConsole:
return Logger_EditorConsole->name();
299 case ELoggerType::TestRunner:
return Logger_TestRunner->name();
301 LK_CORE_ASSERT(
false,
"Unknown logger type: {}",
static_cast<int>(LoggerType));
309 inline static std::shared_ptr<spdlog::logger> Logger_Core =
nullptr;
310 inline static std::shared_ptr<spdlog::logger> Logger_Client =
nullptr;
311 inline static std::shared_ptr<spdlog::logger> Logger_EditorConsole =
nullptr;
312 inline static std::shared_ptr<spdlog::logger> Logger_TestRunner =
nullptr;
315 inline static std::map<std::string, FTagDetails> EnabledTags;
322 template<
typename... TArgs>
323 #if defined(LK_ENGINE_MSVC)
325 std::format_string<TArgs...> Format, TArgs&&... Args)
326 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
328 fmt::format_string<TArgs...> Format, TArgs&&... Args)
331 FTagDetails& TagDetails = EnabledTags[GetLoggerName(LoggerType).data()];
332 if (TagDetails.Enabled && TagDetails.Filter <= Level)
337 case ELogLevel::Trace:
338 Logger->trace(Format, std::forward<TArgs>(Args)...);
340 case ELogLevel::Debug:
341 Logger->debug(Format, std::forward<TArgs>(Args)...);
343 case ELogLevel::Info:
344 Logger->info(Format, std::forward<TArgs>(Args)...);
346 case ELogLevel::Warning:
347 Logger->warn(Format, std::forward<TArgs>(Args)...);
349 case ELogLevel::Error:
350 Logger->error(Format, std::forward<TArgs>(Args)...);
352 case ELogLevel::Fatal:
353 Logger->critical(Format, std::forward<TArgs>(Args)...);
359 template<
typename... TArgs>
360 #if defined(LK_ENGINE_MSVC)
362 std::format_string<TArgs...> Format, TArgs&&... Args)
363 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
365 fmt::format_string<TArgs...> Format, TArgs&&... Args)
368 const FTagDetails& TagDetails = EnabledTags[GetLoggerName(LoggerType).data()];
369 if (TagDetails.Enabled && (TagDetails.Filter <= Level))
371 #if defined(LK_PLATFORM_WINDOWS)
372 const std::string FormattedString = std::format(Format, std::forward<TArgs>(Args)...);
373 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
374 const std::string FormattedString = fmt::format(Format, std::forward<TArgs>(Args)...);
379 case ELogLevel::Trace:
380 Logger->trace(
"[{0}] {1}", Tag, FormattedString);
382 case ELogLevel::Debug:
383 Logger->debug(
"[{0}] {1}", Tag, FormattedString);
385 case ELogLevel::Info:
386 Logger->info(
"[{0}] {1}", Tag, FormattedString);
388 case ELogLevel::Warning:
389 Logger->warn(
"[{0}] {1}", Tag, FormattedString);
391 case ELogLevel::Error:
392 Logger->error(
"[{0}] {1}", Tag, FormattedString);
394 case ELogLevel::Fatal:
395 Logger->critical(
"[{0}] {1}", Tag, FormattedString);
402 std::string_view Tag, std::string_view Message)
404 FTagDetails& TagDetails = EnabledTags[GetLoggerName(LoggerType).data()];
405 if (TagDetails.Enabled && TagDetails.Filter <= Level)
410 case ELogLevel::Trace:
411 Logger->trace(
"[{0}] {1}", Tag, Message);
413 case ELogLevel::Debug:
414 Logger->debug(
"[{0}] {1}", Tag, Message);
416 case ELogLevel::Info:
417 Logger->info(
"[{0}] {1}", Tag, Message);
419 case ELogLevel::Warning:
420 Logger->warn(
"[{0}] {1}", Tag, Message);
422 case ELogLevel::Error:
423 Logger->error(
"[{0}] {1}", Tag, Message);
425 case ELogLevel::Fatal:
426 Logger->critical(
"[{0}] {1}", Tag, Message);
433 template<
typename... TArgs>
434 #if defined(LK_ENGINE_MSVC)
435 FORCEINLINE
void LLog::PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Prefix,
436 std::format_string<TArgs...> Format, TArgs&&... Args)
437 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
438 FORCEINLINE
void LLog::PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Prefix,
439 fmt::format_string<TArgs...> Format, TArgs&&... Args)
442 #if defined(LK_PLATFORM_WINDOWS)
443 const std::string FormattedString = std::format(Format, std::forward<TArgs>(Args)...);
444 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
445 const std::string FormattedString = fmt::format(Format, std::forward<TArgs>(Args)...);
447 if (
auto Logger = GetLogger(LoggerType); Logger !=
nullptr)
449 Logger->error(
"{0}: {1}", Prefix, FormattedString);
453 PrintLn(
"{2}{0}: {1}{3}", Prefix, FormattedString, LK_ANSI_COLOR_BG_BRIGHT_RED, LK_ANSI_COLOR_RESET);
456 #if LK_ENGINE_CONSOLE_ENABLED
457 LK_CONSOLE_FATAL(
"{}", FormattedString);
459 #if LK_ASSERT_MESSAGE_BOX
460 MessageBoxA(
nullptr, FormattedString.c_str(),
"LkEngine Error", (MB_OK | MB_ICONERROR));
464 FORCEINLINE
void LLog::PrintAssertMessage(
const ELoggerType LoggerType, std::string_view Message)
466 if (
auto Logger =
GetLogger(LoggerType); Logger !=
nullptr)
472 PrintLn(
"{1}{0}{2}", Message, LK_ANSI_COLOR_BG_BRIGHT_RED, LK_ANSI_COLOR_RESET);
475 #if LK_ENGINE_CONSOLE_ENABLED
476 LK_CONSOLE_FATAL(
"{}", Message);
478 #if LK_ASSERT_MESSAGE_BOX
479 MessageBoxA(
nullptr, Message.data(),
"LkEngine Error", (MB_OK | MB_ICONERROR));
495 static bool CompareLogFiles(
const std::filesystem::directory_entry& A,
const std::filesystem::directory_entry& B)
497 return (A.path().filename().string() < B.path().filename().string());
501 static int CountLogFilesInDir(
const std::filesystem::path& InDirectory)
503 namespace fs = std::filesystem;
505 if (fs::exists(InDirectory) && fs::is_directory(InDirectory))
507 for (
const fs::directory_entry& Entry : fs::directory_iterator(InDirectory))
509 if (Entry.is_regular_file() && Entry.path().extension() ==
".log")
519 static void CleanLogDirectory(
const std::filesystem::path& InDirectory,
const int MaxLogFiles)
521 namespace fs = std::filesystem;
522 std::vector<fs::directory_entry> LogFiles;
523 LogFiles.reserve(MaxLogFiles);
526 if (fs::exists(InDirectory) && fs::is_directory(InDirectory))
528 for (
const auto& Entry : fs::directory_iterator(InDirectory))
530 if (Entry.is_regular_file() && Entry.path().extension() ==
".log")
532 LogFiles.push_back(Entry);
538 if (LogFiles.size() > MaxLogFiles)
541 std::sort(LogFiles.begin(), LogFiles.end(), CompareLogFiles);
544 for (std::size_t Index = 0; Index < LogFiles.size() - MaxLogFiles; Index++)
546 const fs::directory_entry& LogFile = LogFiles[Index];
547 if (LogFile.path().extension() ==
".log")
549 fs::remove(LogFile.path());
Core macros used by the entire engine.
static void Initialize(std::string_view LogfileName="")
Definition Log.cpp:60
static void PrintMessageWithTag(const ELoggerType LoggerType, const ELogLevel Level, std::string_view Tag, std::string_view Message)
Print a formatted message.
Definition Log.h:401
static FORCEINLINE std::shared_ptr< spdlog::logger > & GetLogger(const ELoggerType LoggerType)
Get a logger instance with the help of a logger type.
Definition Log.h:134
static FORCEINLINE spdlog::level::level_enum ToSpdlogLevel(const ELogLevel Level)
Definition Log.h:263
ELoggerType
Definition Log.h:89
ELogLevel
Definition Log.h:75