feat(logger): create more modular logger
This commit is contained in:
parent
1015569263
commit
51de852ab1
@ -9,5 +9,6 @@
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
#include <utility>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
@ -17,42 +17,65 @@ namespace ICEngine {
|
||||
FATAL
|
||||
};
|
||||
|
||||
class Logger {
|
||||
private:
|
||||
Logger(const char *name, std::ostream *stream) : name(name) {
|
||||
if (stream) {
|
||||
streams.push_back(std::unique_ptr<std::ostream>(stream));
|
||||
}
|
||||
}
|
||||
|
||||
friend class Log;
|
||||
|
||||
class LogSink {
|
||||
public:
|
||||
virtual ~LogSink() = default;
|
||||
|
||||
virtual void Log(const std::string &message) = 0;
|
||||
};
|
||||
|
||||
class ConsoleSink : public LogSink {
|
||||
public:
|
||||
void Log(const std::string &message) override {
|
||||
std::cout << message << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class FileSink : public LogSink {
|
||||
public:
|
||||
explicit FileSink(const std::string &filename) {
|
||||
fileStream.open(filename);
|
||||
}
|
||||
|
||||
void Log(const std::string &message) override {
|
||||
if (fileStream.is_open()) {
|
||||
fileStream << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream fileStream;
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
explicit Logger(const char *name) : name(name) {
|
||||
}
|
||||
|
||||
void SetLevel(LogLevel level) {
|
||||
this->level = level;
|
||||
}
|
||||
|
||||
void AddStream(std::unique_ptr<std::ostream> stream) {
|
||||
this->streams.push_back(std::move(stream));
|
||||
void AddSink(std::shared_ptr<LogSink> sink) {
|
||||
sinks.push_back(std::move(sink));
|
||||
}
|
||||
|
||||
template<typename... 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: Allow user to create their own class that inherits Fatal Handler so they can implement it themselves
|
||||
if (level < this->level) return;
|
||||
std::string formattedMessage = format(formatStr, std::forward<Args>(args)...);
|
||||
std::string logMessage = formatMessage(level, file, line, func, formattedMessage);
|
||||
|
||||
for (const auto &stream: streams) {
|
||||
(*stream) << logMessage << std::endl;
|
||||
std::string logMessage = formatMessage(level, file, line, func,
|
||||
format(formatStr, std::forward<Args>(args)...));
|
||||
|
||||
for (const auto &sink: sinks) {
|
||||
sink->Log(logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const char *name;
|
||||
std::vector<std::unique_ptr<std::ostream> > streams;
|
||||
std::vector<std::shared_ptr<LogSink> > sinks;
|
||||
LogLevel level = DEBUG;
|
||||
|
||||
static const char *levelToString(LogLevel level) {
|
||||
@ -130,17 +153,16 @@ namespace ICEngine {
|
||||
}
|
||||
GetCoreLogger();
|
||||
GetAppLogger();
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Logger> &GetCoreLogger() {
|
||||
static std::shared_ptr<Logger> CoreLogger(new Logger("CORE", &std::cout));
|
||||
static std::shared_ptr<Logger> CoreLogger(new Logger("CORE"));
|
||||
return CoreLogger;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Logger> &GetAppLogger() {
|
||||
static std::shared_ptr<Logger> AppLogger(new Logger("APP", &std::cout));
|
||||
static std::shared_ptr<Logger> AppLogger(new Logger("APP"));
|
||||
return AppLogger;
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,20 @@
|
||||
void ShowLogger();
|
||||
|
||||
int main() {
|
||||
try {
|
||||
ShowLogger();
|
||||
ICEngine::StartApplication();
|
||||
} catch (const std::exception& e) {
|
||||
CORE_LOG_FATAL("Unhandled exception: {}", e.what());
|
||||
return -1;
|
||||
} catch (...) {
|
||||
CORE_LOG_FATAL("Unknown fatal error occurred.");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ShowLogger() {
|
||||
// The logger needs to be initialized before you can use it.
|
||||
// This will be done by the engine, NEVER the user.
|
||||
@ -39,11 +48,8 @@ void ShowLogger() {
|
||||
// You need to create a unique pointer, because the logger will
|
||||
// take ownership of the streams and clean them up when the app
|
||||
// is complete
|
||||
auto coreFileStream = std::make_unique<std::ofstream>("core_logs.txt");
|
||||
auto appFileStream = std::make_unique<std::ofstream>("app_logs.txt");
|
||||
|
||||
ICEngine::Log::GetCoreLogger()->AddStream(std::move(coreFileStream));
|
||||
ICEngine::Log::GetAppLogger()->AddStream(std::move(appFileStream));
|
||||
ICEngine::Log::GetCoreLogger()->AddSink(std::make_shared<ICEngine::FileSink>("core_logs.txt"));
|
||||
ICEngine::Log::GetAppLogger()->AddSink(std::make_shared<ICEngine::FileSink>("app_logs.txt"));
|
||||
|
||||
// You can log multiple different types with formatting
|
||||
int age = 30;
|
||||
|
@ -5,7 +5,5 @@
|
||||
#include <ICEngine.hpp>
|
||||
|
||||
int main() {
|
||||
Logger logger;
|
||||
logger.logVersion();
|
||||
return 0;
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user