feat(logger): handles ownership of streams

This commit is contained in:
illyum 2024-09-16 23:27:50 -06:00
parent 567c1ae1c0
commit b17c160d5c
2 changed files with 28 additions and 14 deletions

View File

@ -8,5 +8,6 @@
#include <chrono> #include <chrono>
#include <cstdarg> #include <cstdarg>
#include <iomanip> #include <iomanip>
#include <utility>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>

View File

@ -7,7 +7,6 @@
#include <pch.hpp> #include <pch.hpp>
namespace ICEngine { namespace ICEngine {
enum LogLevel { enum LogLevel {
OFF = 0, OFF = 0,
TRACE, TRACE,
@ -22,9 +21,10 @@ namespace ICEngine {
private: private:
Logger(const char *name, std::ostream *stream) : name(name) { Logger(const char *name, std::ostream *stream) : name(name) {
if (stream) { if (stream) {
streams.push_back(stream); streams.push_back(std::unique_ptr<std::ostream>(stream));
} }
} }
friend class Log; friend class Log;
public: public:
@ -32,26 +32,27 @@ namespace ICEngine {
this->level = level; this->level = level;
} }
void AddStream(std::ostream * stream) { void AddStream(std::unique_ptr<std::ostream> stream) {
this->streams.push_back(stream); this->streams.push_back(std::move(stream));
} }
template<typename... Args> template<typename... Args>
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: 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 // TODO: Allow user to create their own class that inherits Fatal Handler so they can implement it themselves
if (level < this->level) return; if (level < this->level) return;
std::string formattedMessage = format(formatStr, std::forward<Args>(args)...); std::string formattedMessage = format(formatStr, std::forward<Args>(args)...);
std::string logMessage = formatMessage(level, file, line, func, formattedMessage); std::string logMessage = formatMessage(level, file, line, func, formattedMessage);
for (auto stream: streams) { for (const auto &stream: streams) {
(*stream) << logMessage << std::endl; (*stream) << logMessage << std::endl;
} }
} }
private: private:
const char *name; const char *name;
std::vector<std::ostream *> streams; std::vector<std::unique_ptr<std::ostream> > streams;
LogLevel level = DEBUG; LogLevel level = DEBUG;
static const char *levelToString(LogLevel level) { static const char *levelToString(LogLevel level) {
@ -84,7 +85,7 @@ namespace ICEngine {
} }
template<typename... Args> template<typename... Args>
std::string format(const std::string &formatStr, Args&&... args) { std::string format(const std::string &formatStr, Args &&... args) {
std::ostringstream oss; std::ostringstream oss;
formatHelper(oss, formatStr, std::forward<Args>(args)...); formatHelper(oss, formatStr, std::forward<Args>(args)...);
return oss.str(); return oss.str();
@ -95,7 +96,8 @@ namespace ICEngine {
} }
template<typename T, typename... Args> template<typename T, typename... Args>
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("{}"); size_t pos = formatStr.find("{}");
if (pos != std::string::npos) { if (pos != std::string::npos) {
oss << formatStr.substr(0, pos) << std::forward<T>(firstArg); oss << formatStr.substr(0, pos) << std::forward<T>(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,
std::string formatMessage(LogLevel level, const char *file, int line, const char *func, const std::string &message) { const std::string &message) {
std::ostringstream oss; std::ostringstream oss;
oss << getCurrentTime() << " "; oss << getCurrentTime() << " ";
oss << truncateFilePath(file) << ":" << line << ":" << func << " "; oss << truncateFilePath(file) << ":" << line << ":" << func << " ";
oss << "[" << levelToString(level) << "] "; oss << "[" << name << "] ";
oss << "[" << name << "]: " << message; oss << "[" << levelToString(level) << "]: ";
oss << message;
return oss.str(); return oss.str();
} }
}; };
@ -119,8 +122,16 @@ namespace ICEngine {
class Log { class Log {
public: public:
static void Init() { static void Init() {
static bool isInitialized = false;
if (isInitialized) {
GetCoreLogger()->Log(WARN, __FILE__, __LINE__, __FUNCTION__,
"Logger already initialized. Skipping re-initialization.");
return;
}
GetCoreLogger(); GetCoreLogger();
GetAppLogger(); GetAppLogger();
isInitialized = true;
} }
static std::shared_ptr<Logger> &GetCoreLogger() { static std::shared_ptr<Logger> &GetCoreLogger() {
@ -135,7 +146,9 @@ namespace ICEngine {
private: private:
Log() = delete; Log() = delete;
Log(const Log &) = delete; Log(const Log &) = delete;
Log &operator=(const Log &) = delete; Log &operator=(const Log &) = delete;
}; };
@ -167,5 +180,5 @@ namespace ICEngine {
#define LOG_ERROR(message, ...) #define LOG_ERROR(message, ...)
#define LOG_CRITICAL(message, ...) #define LOG_CRITICAL(message, ...)
#define LOG_FATAL(message, ...) #define LOG_FATAL(message, ...)
#endif #endif
} }