diff --git a/src/Logger.cpp b/src/Logger.cpp index d584421..4b47fa1 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -1,109 +1,63 @@ #include "Logger.h" +#include "FatalHandler.h" -void Logger::Initialize(const std::string &logFile, LogLevel consoleLevel, LogLevel fileLevel) { - logFileName = logFile; - consoleLogLevel = consoleLevel; - fileLogLevel = fileLevel; - if (!logFile.empty()) { - logFileStream.open(logFile, std::ios::out | std::ios::app); +Logger& Logger::GetCoreLogger() { + static Logger coreLogger; + return coreLogger; +} + +Logger& Logger::GetAppLogger() { + static Logger appLogger; + return appLogger; +} + +Logger::Logger() {} + +void Logger::AddOutputStream(std::ostream* stream) { + outputStreams.push_back(stream); +} + +void Logger::SetLogLevel(LogLevel level) { + logLevel = level; +} + +void Logger::Log(LogLevel level, const std::string& message) { + if (level >= logLevel) { + LogInternal(level, message); } } -Logger::~Logger() { - if (logFileStream.is_open()) { - logFileStream.close(); +void Logger::LogInternal(LogLevel level, const std::string& message) { + std::string time = GetCurrentTime(); + std::string levelStr = LevelToString(level); + + for (auto* stream : outputStreams) { + *stream << time << " [" << levelStr << "]: " << message << std::endl; } } -void Logger::Log(LogLevel level, const std::string& message, const std::string& scope) { - std::lock_guard lock(logMutex); +std::string Logger::GetCurrentTime() { + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); - std::string formattedMessage = FormatMessage(level, message, scope); - - memoryLogs.push_back(formattedMessage); - if (memoryLogs.size() > memoryLogSize) { - memoryLogs.pop_front(); - } - - if (ShouldLogToConsole(level)) { - std::cout << formattedMessage << std::endl; - } - - if (ShouldLogToFile(level)) { - if (logFileStream.is_open()) { - logFileStream << formattedMessage << std::endl; - } - } + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t), "%Y/%m/%d %H:%M:%S"); + return ss.str(); } -void Logger::LogInfo(const std::string& message, const std::string& scope) { - Log(LogLevel::INFOL, message, scope); -} - -void Logger::LogDebug(const std::string& message, const std::string& scope) { - Log(LogLevel::DEBUGL, message, scope); -} - -void Logger::LogWarning(const std::string& message, const std::string& scope) { - Log(LogLevel::WARNINGL, message, scope); -} - -void Logger::LogError(const std::string& message, const std::string& scope) { - Log(LogLevel::ERRORL, message, scope); -} - -void Logger::LogCritical(const std::string& message, const std::string& scope) { - Log(LogLevel::CRITICALL, message, scope); -} - -void Logger::DumpLogs(const std::string& dumpFileName) { - std::lock_guard lock(logMutex); - - std::ofstream dumpFile(dumpFileName, std::ios::out | std::ios::app); - if (!dumpFile.is_open()) { - std::cerr << "Failed to open dump file: " << dumpFileName << std::endl; - return; - } - - dumpFile << "---- Log Dump ----" << std::endl; - dumpFile << "Timestamp: " << GetTimestamp() << std::endl; - dumpFile << "------------------" << std::endl; - - for (const std::string& log : memoryLogs) { - dumpFile << log << std::endl; - } - - dumpFile.close(); -} - -std::string Logger::FormatMessage(LogLevel level, const std::string& message, const std::string& scope) { - std::string levelStr = LogLevelToString(level); - std::string timestamp = GetTimestamp(); - return timestamp + " [" + levelStr + "] [" + scope + "] " + message; -} - -std::string Logger::GetTimestamp() { - std::time_t now = std::time(nullptr); - char buf[20]; - std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now)); - return std::string(buf); -} - -std::string Logger::LogLevelToString(LogLevel level) { +std::string Logger::LevelToString(LogLevel level) { switch (level) { - case LogLevel::DEBUGL: return "DEBUG"; - case LogLevel::INFOL: return "INFO"; - case LogLevel::WARNINGL: return "WARNING"; - case LogLevel::ERRORL: return "ERROR"; - case LogLevel::CRITICALL: return "CRITICAL"; - default: return "UNKNOWN"; + case LogLevel::TRACE_l: return "TRACE"; + case LogLevel::DEBUG_l: return "DEBUG"; + case LogLevel::INFO_l: return "INFO"; + case LogLevel::WARN_l: return "WARN"; + case LogLevel::ERROR_l: return "ERROR"; + case LogLevel::FATAL_l: return "FATAL"; + default: return "UNKNOWN"; } } -bool Logger::ShouldLogToConsole(LogLevel level) { - return level >= consoleLogLevel; -} - -bool Logger::ShouldLogToFile(LogLevel level) { - return level >= fileLogLevel && !logFileName.empty(); -} +template +void Logger::FatalHandler(const std::string& format, Args... args) { + IsoEngine::FatalHandler(format, args...); +} \ No newline at end of file diff --git a/src/Logger.h b/src/Logger.h index 6372dfe..07a4eb1 100644 --- a/src/Logger.h +++ b/src/Logger.h @@ -1,49 +1,77 @@ #pragma once +#include + enum class LogLevel { - DEBUGL = 0, - INFOL = 10, - WARNINGL = 20, - ERRORL = 30, - CRITICALL = 40 + TRACE_l, + DEBUG_l, + INFO_l, + WARN_l, + ERROR_l, + FATAL_l }; class Logger { public: - static Logger& GetInstance() { - static Logger instance; - return instance; + static Logger& GetCoreLogger(); + static Logger& GetAppLogger(); + + void Log(LogLevel level, const std::string& message); + + template + void LogFormat(LogLevel level, const std::string& format, Args&&... args) { + if (level >= logLevel) { + std::string formattedMessage = std::vformat(format, std::make_format_args(std::forward(args)...)); + LogInternal(level, formattedMessage); + } } - Logger(const Logger&) = delete; - Logger& operator=(const Logger&) = delete; + void AddOutputStream(std::ostream* stream); + void SetLogLevel(LogLevel level); - void Initialize(const std::string &logFile = "", LogLevel consoleLevel = LogLevel::DEBUGL, LogLevel fileLevel = LogLevel::DEBUGL); - void Log(LogLevel level, const std::string &message, const std::string &scope = ""); - void LogDebug(const std::string& message, const std::string& scope = ""); - void LogInfo(const std::string& message, const std::string& scope = ""); - void LogWarning(const std::string& message, const std::string& scope = ""); - void LogError(const std::string& message, const std::string& scope = ""); - void LogCritical(const std::string& message, const std::string& scope = ""); - - void DumpLogs(const std::string& dumpFileName = "crash_dump.log"); + template + static void FatalHandler(const std::string& format, Args... args); private: - Logger() = default; - ~Logger(); + Logger(); + void LogInternal(LogLevel level, const std::string& message); + std::string GetCurrentTime(); + std::string LevelToString(LogLevel level); - std::ofstream logFileStream; - std::string logFileName; - LogLevel consoleLogLevel; - LogLevel fileLogLevel; - std::mutex logMutex; - - std::deque memoryLogs; - size_t memoryLogSize = 100; - - std::string FormatMessage(LogLevel level, const std::string& message, const std::string& scope); - std::string GetTimestamp(); - std::string LogLevelToString(LogLevel level); - bool ShouldLogToConsole(LogLevel level); - bool ShouldLogToFile(LogLevel level); + std::vector outputStreams; + LogLevel logLevel = LogLevel::TRACE_l; }; + +#ifdef ENABLE_LOGGING + +#define LOG_TRACE(...) Logger::GetAppLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__) +#define LOG_DEBUG(...) Logger::GetAppLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__) +#define LOG_INFO(...) Logger::GetAppLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__) +#define LOG_WARN(...) Logger::GetAppLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__) +#define LOG_ERROR(...) Logger::GetAppLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__) +#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__) + +#define CORE_LOG_TRACE(...) Logger::GetCoreLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__) +#define CORE_LOG_DEBUG(...) Logger::GetCoreLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__) +#define CORE_LOG_INFO(...) Logger::GetCoreLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__) +#define CORE_LOG_WARN(...) Logger::GetCoreLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__) +#define CORE_LOG_ERROR(...) Logger::GetCoreLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__) +#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__) + +#else + +#define LOG_TRACE(...) +#define LOG_DEBUG(...) +#define LOG_INFO(...) +#define LOG_WARN(...) +#define LOG_ERROR(...) +#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__) + +#define CORE_LOG_TRACE(...) +#define CORE_LOG_DEBUG(...) +#define CORE_LOG_INFO(...) +#define CORE_LOG_WARN(...) +#define CORE_LOG_ERROR(...) +#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__) + +#endif