ISXMr/src/Logger.h

109 lines
2.8 KiB
C++

//
// Created by marob on 12/27/2023.
//
#ifndef LOGGER_H
#define LOGGER_H
#include "ISXMr.h"
#include <sstream>
#include <iostream>
#include <iomanip>
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<typename T>
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::ostream& (*)(std::ostream &)>(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