// // Created by marob on 12/27/2023. // #ifndef LOGGER_H #define LOGGER_H #include "ISXMr.h" #include #include #include enum class LogLevel { Debug, Info, Warning, Error }; class Logger { public: Logger(const Logger &) = delete; Logger &operator=(const Logger &) = delete; static Logger &instance() { static Logger singleton; return singleton; } void SetLogLevel(LogLevel level) { currentLogLevel = level; } Logger &operator<<(LogLevel level) { SetLogLevel(level); return *this; } template Logger &operator<<(const T &value) { std::ostringstream &tss = getThreadLocalStream(); tss << value; return *this; } Logger &operator<<(std::ostream & (*pf)(std::ostream &)) { std::ostringstream &tss = getThreadLocalStream(); pf(tss); if (pf == static_cast(std::endl)) { string str = tss.str(); pISInterface->Printf(formatMessage(str).c_str()); tss.str(""); tss.clear(); } return *this; } private: Logger() = default; LogLevel currentLogLevel = LogLevel::Info; static std::ostringstream &getThreadLocalStream() { thread_local std::ostringstream tss; return tss; } static void rtrim_newlines(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](const unsigned char ch) { return ch != '\n' && ch != '\r'; }).base(), s.end()); } std::string formatMessage(std::string &message) const { const auto now = std::chrono::system_clock::now(); const auto now_c = std::chrono::system_clock::to_time_t(now); std::tm now_tm; localtime_s(&now_tm, &now_c); // Thread-safe on Windows std::ostringstream oss; rtrim_newlines(message); oss << "[" << std::put_time(&now_tm, "%H:%M:%S") << "] - " << getColorCode(currentLogLevel) << message << "\ax"; // Reset color to default at the end return oss.str(); } static std::string getColorCode(const LogLevel level) { switch (level) { case LogLevel::Debug: return "\ay"; // Yellow case LogLevel::Info: return "\ag"; // Green case LogLevel::Warning: return "\ao"; // Orange case LogLevel::Error: return "\ar"; // Red default: return "\aw"; // White } } }; // Global logger instance for ease of access #define logger Logger::instance() #define log Logger::instance() << LogLevel::Info #define logd Logger::instance() << LogLevel::Debug #define logw Logger::instance() << LogLevel::Warning #define loge Logger::instance() << LogLevel::Error #endif //LOGGER_H