feat(logging): improve logging and add log macros
This commit is contained in:
parent
0fa35696bb
commit
fef4a92378
142
src/Logger.cpp
142
src/Logger.cpp
@ -1,109 +1,63 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "FatalHandler.h"
|
||||||
|
|
||||||
void Logger::Initialize(const std::string &logFile, LogLevel consoleLevel, LogLevel fileLevel) {
|
Logger& Logger::GetCoreLogger() {
|
||||||
logFileName = logFile;
|
static Logger coreLogger;
|
||||||
consoleLogLevel = consoleLevel;
|
return coreLogger;
|
||||||
fileLogLevel = fileLevel;
|
}
|
||||||
if (!logFile.empty()) {
|
|
||||||
logFileStream.open(logFile, std::ios::out | std::ios::app);
|
Logger& Logger::GetAppLogger() {
|
||||||
|
static Logger appLogger;
|
||||||
|
return appLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Logger() {}
|
||||||
|
|
||||||
|
void Logger::AddOutputStream(std::ostream* stream) {
|
||||||
|
outputStreams.push_back(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetLogLevel(LogLevel level) {
|
||||||
|
logLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Log(LogLevel level, const std::string& message) {
|
||||||
|
if (level >= logLevel) {
|
||||||
|
LogInternal(level, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::~Logger() {
|
void Logger::LogInternal(LogLevel level, const std::string& message) {
|
||||||
if (logFileStream.is_open()) {
|
std::string time = GetCurrentTime();
|
||||||
logFileStream.close();
|
std::string levelStr = LevelToString(level);
|
||||||
|
|
||||||
|
for (auto* stream : outputStreams) {
|
||||||
|
*stream << time << " [" << levelStr << "]: " << message << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Log(LogLevel level, const std::string& message, const std::string& scope) {
|
std::string Logger::GetCurrentTime() {
|
||||||
std::lock_guard<std::mutex> lock(logMutex);
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||||
|
|
||||||
std::string formattedMessage = FormatMessage(level, message, scope);
|
std::stringstream ss;
|
||||||
|
ss << std::put_time(std::localtime(&in_time_t), "%Y/%m/%d %H:%M:%S");
|
||||||
memoryLogs.push_back(formattedMessage);
|
return ss.str();
|
||||||
if (memoryLogs.size() > memoryLogSize) {
|
|
||||||
memoryLogs.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ShouldLogToConsole(level)) {
|
|
||||||
std::cout << formattedMessage << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ShouldLogToFile(level)) {
|
|
||||||
if (logFileStream.is_open()) {
|
|
||||||
logFileStream << formattedMessage << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::LogInfo(const std::string& message, const std::string& scope) {
|
std::string Logger::LevelToString(LogLevel level) {
|
||||||
Log(LogLevel::INFOL, message, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::LogDebug(const std::string& message, const std::string& scope) {
|
|
||||||
Log(LogLevel::DEBUGL, message, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::LogWarning(const std::string& message, const std::string& scope) {
|
|
||||||
Log(LogLevel::WARNINGL, message, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::LogError(const std::string& message, const std::string& scope) {
|
|
||||||
Log(LogLevel::ERRORL, message, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::LogCritical(const std::string& message, const std::string& scope) {
|
|
||||||
Log(LogLevel::CRITICALL, message, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::DumpLogs(const std::string& dumpFileName) {
|
|
||||||
std::lock_guard<std::mutex> lock(logMutex);
|
|
||||||
|
|
||||||
std::ofstream dumpFile(dumpFileName, std::ios::out | std::ios::app);
|
|
||||||
if (!dumpFile.is_open()) {
|
|
||||||
std::cerr << "Failed to open dump file: " << dumpFileName << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpFile << "---- Log Dump ----" << std::endl;
|
|
||||||
dumpFile << "Timestamp: " << GetTimestamp() << std::endl;
|
|
||||||
dumpFile << "------------------" << std::endl;
|
|
||||||
|
|
||||||
for (const std::string& log : memoryLogs) {
|
|
||||||
dumpFile << log << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Logger::FormatMessage(LogLevel level, const std::string& message, const std::string& scope) {
|
|
||||||
std::string levelStr = LogLevelToString(level);
|
|
||||||
std::string timestamp = GetTimestamp();
|
|
||||||
return timestamp + " [" + levelStr + "] [" + scope + "] " + message;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Logger::GetTimestamp() {
|
|
||||||
std::time_t now = std::time(nullptr);
|
|
||||||
char buf[20];
|
|
||||||
std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
|
|
||||||
return std::string(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Logger::LogLevelToString(LogLevel level) {
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LogLevel::DEBUGL: return "DEBUG";
|
case LogLevel::TRACE_l: return "TRACE";
|
||||||
case LogLevel::INFOL: return "INFO";
|
case LogLevel::DEBUG_l: return "DEBUG";
|
||||||
case LogLevel::WARNINGL: return "WARNING";
|
case LogLevel::INFO_l: return "INFO";
|
||||||
case LogLevel::ERRORL: return "ERROR";
|
case LogLevel::WARN_l: return "WARN";
|
||||||
case LogLevel::CRITICALL: return "CRITICAL";
|
case LogLevel::ERROR_l: return "ERROR";
|
||||||
default: return "UNKNOWN";
|
case LogLevel::FATAL_l: return "FATAL";
|
||||||
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::ShouldLogToConsole(LogLevel level) {
|
template<typename... Args>
|
||||||
return level >= consoleLogLevel;
|
void Logger::FatalHandler(const std::string& format, Args... args) {
|
||||||
}
|
IsoEngine::FatalHandler(format, args...);
|
||||||
|
}
|
||||||
bool Logger::ShouldLogToFile(LogLevel level) {
|
|
||||||
return level >= fileLogLevel && !logFileName.empty();
|
|
||||||
}
|
|
98
src/Logger.h
98
src/Logger.h
@ -1,49 +1,77 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <IsoEnginePCH.h>
|
||||||
|
|
||||||
enum class LogLevel {
|
enum class LogLevel {
|
||||||
DEBUGL = 0,
|
TRACE_l,
|
||||||
INFOL = 10,
|
DEBUG_l,
|
||||||
WARNINGL = 20,
|
INFO_l,
|
||||||
ERRORL = 30,
|
WARN_l,
|
||||||
CRITICALL = 40
|
ERROR_l,
|
||||||
|
FATAL_l
|
||||||
};
|
};
|
||||||
|
|
||||||
class Logger {
|
class Logger {
|
||||||
public:
|
public:
|
||||||
static Logger& GetInstance() {
|
static Logger& GetCoreLogger();
|
||||||
static Logger instance;
|
static Logger& GetAppLogger();
|
||||||
return instance;
|
|
||||||
|
void Log(LogLevel level, const std::string& message);
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void LogFormat(LogLevel level, const std::string& format, Args&&... args) {
|
||||||
|
if (level >= logLevel) {
|
||||||
|
std::string formattedMessage = std::vformat(format, std::make_format_args(std::forward<Args>(args)...));
|
||||||
|
LogInternal(level, formattedMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger(const Logger&) = delete;
|
void AddOutputStream(std::ostream* stream);
|
||||||
Logger& operator=(const Logger&) = delete;
|
void SetLogLevel(LogLevel level);
|
||||||
|
|
||||||
void Initialize(const std::string &logFile = "", LogLevel consoleLevel = LogLevel::DEBUGL, LogLevel fileLevel = LogLevel::DEBUGL);
|
template<typename... Args>
|
||||||
void Log(LogLevel level, const std::string &message, const std::string &scope = "");
|
static void FatalHandler(const std::string& format, Args... args);
|
||||||
void LogDebug(const std::string& message, const std::string& scope = "");
|
|
||||||
void LogInfo(const std::string& message, const std::string& scope = "");
|
|
||||||
void LogWarning(const std::string& message, const std::string& scope = "");
|
|
||||||
void LogError(const std::string& message, const std::string& scope = "");
|
|
||||||
void LogCritical(const std::string& message, const std::string& scope = "");
|
|
||||||
|
|
||||||
void DumpLogs(const std::string& dumpFileName = "crash_dump.log");
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger() = default;
|
Logger();
|
||||||
~Logger();
|
void LogInternal(LogLevel level, const std::string& message);
|
||||||
|
std::string GetCurrentTime();
|
||||||
|
std::string LevelToString(LogLevel level);
|
||||||
|
|
||||||
std::ofstream logFileStream;
|
std::vector<std::ostream*> outputStreams;
|
||||||
std::string logFileName;
|
LogLevel logLevel = LogLevel::TRACE_l;
|
||||||
LogLevel consoleLogLevel;
|
|
||||||
LogLevel fileLogLevel;
|
|
||||||
std::mutex logMutex;
|
|
||||||
|
|
||||||
std::deque<std::string> memoryLogs;
|
|
||||||
size_t memoryLogSize = 100;
|
|
||||||
|
|
||||||
std::string FormatMessage(LogLevel level, const std::string& message, const std::string& scope);
|
|
||||||
std::string GetTimestamp();
|
|
||||||
std::string LogLevelToString(LogLevel level);
|
|
||||||
bool ShouldLogToConsole(LogLevel level);
|
|
||||||
bool ShouldLogToFile(LogLevel level);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_LOGGING
|
||||||
|
|
||||||
|
#define LOG_TRACE(...) Logger::GetAppLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__)
|
||||||
|
#define LOG_DEBUG(...) Logger::GetAppLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__)
|
||||||
|
#define LOG_INFO(...) Logger::GetAppLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__)
|
||||||
|
#define LOG_WARN(...) Logger::GetAppLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__)
|
||||||
|
#define LOG_ERROR(...) Logger::GetAppLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__)
|
||||||
|
#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define CORE_LOG_TRACE(...) Logger::GetCoreLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__)
|
||||||
|
#define CORE_LOG_DEBUG(...) Logger::GetCoreLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__)
|
||||||
|
#define CORE_LOG_INFO(...) Logger::GetCoreLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__)
|
||||||
|
#define CORE_LOG_WARN(...) Logger::GetCoreLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__)
|
||||||
|
#define CORE_LOG_ERROR(...) Logger::GetCoreLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__)
|
||||||
|
#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define LOG_TRACE(...)
|
||||||
|
#define LOG_DEBUG(...)
|
||||||
|
#define LOG_INFO(...)
|
||||||
|
#define LOG_WARN(...)
|
||||||
|
#define LOG_ERROR(...)
|
||||||
|
#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define CORE_LOG_TRACE(...)
|
||||||
|
#define CORE_LOG_DEBUG(...)
|
||||||
|
#define CORE_LOG_INFO(...)
|
||||||
|
#define CORE_LOG_WARN(...)
|
||||||
|
#define CORE_LOG_ERROR(...)
|
||||||
|
#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user