feat(logging): implement logger and logging macros
This commit is contained in:
parent
9db13726b5
commit
bf2847cc09
@ -6,13 +6,160 @@
|
|||||||
|
|
||||||
#include <pch.hpp>
|
#include <pch.hpp>
|
||||||
|
|
||||||
class Logger {
|
namespace ICEngine {
|
||||||
public:
|
|
||||||
void logVersion() {
|
enum LogLevel {
|
||||||
std::cout << "ICEngine Version: " << PROJECT_VERSION << std::endl;
|
OFF = 0,
|
||||||
|
TRACE,
|
||||||
|
DEBUG,
|
||||||
|
WARN,
|
||||||
|
ERROR,
|
||||||
|
CRITICAL,
|
||||||
|
FATAL
|
||||||
|
};
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
private:
|
||||||
|
Logger(const char *name, std::ostream *stream) : name(name) {
|
||||||
|
if (stream) {
|
||||||
|
streams.push_back(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
friend class Log;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetLevel(LogLevel level) {
|
||||||
|
this->level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void logCrash(const std::string& errorMessage) {
|
template<typename... Args>
|
||||||
std::cerr << "Crash detected in version " << PROJECT_VERSION << ": " << errorMessage << std::endl;
|
void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr, Args &&... args) {
|
||||||
|
if (level < this->level) return;
|
||||||
|
std::string formattedMessage = format(formatStr, std::forward<Args>(args)...);
|
||||||
|
std::string logMessage = formatMessage(level, file, line, func, formattedMessage);
|
||||||
|
|
||||||
|
for (auto stream: streams) {
|
||||||
|
(*stream) << logMessage << std::endl;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *name;
|
||||||
|
std::vector<std::ostream *> streams;
|
||||||
|
LogLevel level = DEBUG;
|
||||||
|
|
||||||
|
static const char *levelToString(LogLevel level) {
|
||||||
|
switch (level) {
|
||||||
|
case TRACE: return "TRACE";
|
||||||
|
case DEBUG: return "DEBUG";
|
||||||
|
case WARN: return "WARN";
|
||||||
|
case ERROR: return "ERROR";
|
||||||
|
case CRITICAL: return "CRITICAL";
|
||||||
|
case FATAL: return "FATAL";
|
||||||
|
default: return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getCurrentTime() {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S");
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string truncateFilePath(const char *file) {
|
||||||
|
std::string path(file);
|
||||||
|
size_t pos = path.find_last_of("/\\");
|
||||||
|
if (pos != std::string::npos && pos > 3) {
|
||||||
|
return "..." + path.substr(pos - 3);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
std::string format(const std::string &formatStr, Args&&... args) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
formatHelper(oss, formatStr, std::forward<Args>(args)...);
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatHelper(std::ostringstream &oss, const std::string &formatStr) {
|
||||||
|
oss << formatStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
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<T>(firstArg);
|
||||||
|
formatHelper(oss, formatStr.substr(pos + 2), std::forward<Args>(remainingArgs)...);
|
||||||
|
} else {
|
||||||
|
oss << formatStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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::ostringstream oss;
|
||||||
|
oss << getCurrentTime() << " ";
|
||||||
|
oss << truncateFilePath(file) << ":" << line << ":" << func << " ";
|
||||||
|
oss << "[" << levelToString(level) << "] ";
|
||||||
|
oss << "[" << name << "]: " << message;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Log {
|
||||||
|
public:
|
||||||
|
static void Init() {
|
||||||
|
GetCoreLogger();
|
||||||
|
GetAppLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Logger> &GetCoreLogger() {
|
||||||
|
static std::shared_ptr<Logger> CoreLogger(new Logger("CORE", &std::cout));
|
||||||
|
return CoreLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Logger> &GetAppLogger() {
|
||||||
|
static std::shared_ptr<Logger> AppLogger(new Logger("APP", &std::cout));
|
||||||
|
return AppLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Log() = delete;
|
||||||
|
Log(const Log &) = delete;
|
||||||
|
Log &operator=(const Log &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define CORE_LOG_TRACE(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::TRACE, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define CORE_LOG_DEBUG(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::DEBUG, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define CORE_LOG_WARN(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::WARN, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define CORE_LOG_ERROR(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::ERROR, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define CORE_LOG_CRITICAL(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::CRITICAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define CORE_LOG_FATAL(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::FATAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define LOG_TRACE(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::TRACE, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define LOG_DEBUG(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::DEBUG, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define LOG_WARN(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::WARN, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define LOG_ERROR(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::ERROR, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define LOG_CRITICAL(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::CRITICAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#define LOG_FATAL(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::FATAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define CORE_LOG_TRACE(message, ...)
|
||||||
|
#define CORE_LOG_DEBUG(message, ...)
|
||||||
|
#define CORE_LOG_WARN(message, ...)
|
||||||
|
#define CORE_LOG_ERROR(message, ...)
|
||||||
|
#define CORE_LOG_CRITICAL(message, ...)
|
||||||
|
#define CORE_LOG_FATAL(message, ...)
|
||||||
|
|
||||||
|
#define LOG_TRACE(message, ...)
|
||||||
|
#define LOG_DEBUG(message, ...)
|
||||||
|
#define LOG_WARN(message, ...)
|
||||||
|
#define LOG_ERROR(message, ...)
|
||||||
|
#define LOG_CRITICAL(message, ...)
|
||||||
|
#define LOG_FATAL(message, ...)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user