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