diff --git a/engine/pch.hpp b/engine/pch.hpp index 2ae76d3..a64a22e 100644 --- a/engine/pch.hpp +++ b/engine/pch.hpp @@ -8,5 +8,6 @@ #include #include #include +#include #include #include diff --git a/engine/src/core/Logger.hpp b/engine/src/core/Logger.hpp index 74bbf3d..150ead6 100644 --- a/engine/src/core/Logger.hpp +++ b/engine/src/core/Logger.hpp @@ -7,7 +7,6 @@ #include namespace ICEngine { - enum LogLevel { OFF = 0, TRACE, @@ -22,9 +21,10 @@ namespace ICEngine { private: Logger(const char *name, std::ostream *stream) : name(name) { if (stream) { - streams.push_back(stream); + streams.push_back(std::unique_ptr(stream)); } } + friend class Log; public: @@ -32,26 +32,27 @@ namespace ICEngine { this->level = level; } - void AddStream(std::ostream * stream) { - this->streams.push_back(stream); + void AddStream(std::unique_ptr stream) { + this->streams.push_back(std::move(stream)); } template - void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr, Args &&... args) { + void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr, + Args &&... args) { // TODO: Create a crash handler and manage fatal messages separately (creates crashdump) // TODO: Allow user to create their own class that inherits Fatal Handler so they can implement it themselves if (level < this->level) return; std::string formattedMessage = format(formatStr, std::forward(args)...); std::string logMessage = formatMessage(level, file, line, func, formattedMessage); - for (auto stream: streams) { + for (const auto &stream: streams) { (*stream) << logMessage << std::endl; } } private: const char *name; - std::vector streams; + std::vector > streams; LogLevel level = DEBUG; static const char *levelToString(LogLevel level) { @@ -84,7 +85,7 @@ namespace ICEngine { } template - std::string format(const std::string &formatStr, Args&&... args) { + std::string format(const std::string &formatStr, Args &&... args) { std::ostringstream oss; formatHelper(oss, formatStr, std::forward(args)...); return oss.str(); @@ -95,7 +96,8 @@ namespace ICEngine { } template - void formatHelper(std::ostringstream &oss, const std::string &formatStr, T &&firstArg, Args&&... remainingArgs) { + void formatHelper(std::ostringstream &oss, const std::string &formatStr, T &&firstArg, + Args &&... remainingArgs) { size_t pos = formatStr.find("{}"); if (pos != std::string::npos) { oss << formatStr.substr(0, pos) << std::forward(firstArg); @@ -105,13 +107,14 @@ namespace ICEngine { } } - // Formats the log message with metadata (timestamp, file, line, etc.) - std::string formatMessage(LogLevel level, const char *file, int line, const char *func, const std::string &message) { + std::string formatMessage(LogLevel level, const char *file, int line, const char *func, + const std::string &message) { std::ostringstream oss; oss << getCurrentTime() << " "; oss << truncateFilePath(file) << ":" << line << ":" << func << " "; - oss << "[" << levelToString(level) << "] "; - oss << "[" << name << "]: " << message; + oss << "[" << name << "] "; + oss << "[" << levelToString(level) << "]: "; + oss << message; return oss.str(); } }; @@ -119,8 +122,16 @@ namespace ICEngine { class Log { public: static void Init() { + static bool isInitialized = false; + if (isInitialized) { + GetCoreLogger()->Log(WARN, __FILE__, __LINE__, __FUNCTION__, + "Logger already initialized. Skipping re-initialization."); + return; + } GetCoreLogger(); GetAppLogger(); + + isInitialized = true; } static std::shared_ptr &GetCoreLogger() { @@ -135,7 +146,9 @@ namespace ICEngine { private: Log() = delete; + Log(const Log &) = delete; + Log &operator=(const Log &) = delete; }; @@ -167,5 +180,5 @@ namespace ICEngine { #define LOG_ERROR(message, ...) #define LOG_CRITICAL(message, ...) #define LOG_FATAL(message, ...) - #endif +#endif }