Vulkan/src/Common/Logger.h
2026-08-18 03:13:38 +02:00

334 lines
6.4 KiB
C++

#ifndef LOGGER_H
#define LOGGER_H
// Custom includes
// Enums
enum class LogModule {
ENGINE,
RENDERER,
GLFW,
CLEANUP
};
enum class LogLevel {
EDEBUG,
EINIT, // Initialization related
EINFO, // General infos
EWARN,
EERROR,
EFATAL
};
class NetLogger {
public:
struct Server{
int priority;
char* url[]; // Put the url at the end for bit optimization
};
void initNetLogger(Server server);
void logNet(char* body[], char* head, Server server);
void logNetAsync(); // Todo
private:
};
class Logger {
public:
// Members
std::string logBuffer; // Log is empty by default
std::vector<std::string_view> lines;
// Functions
template<typename... Args>
void logDisk(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to a file on disk
// Overload
void logDisk(std::string_view message);
template<typename... Args>
void logRAM(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to ram (ImGUI)
template<typename... Args>
void logConsole(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to the console (crashes, etc...)
template<typename... Args>
void logAll(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs using all of the above, RAM then console and finally disk, maybe multithread (?)
template<typename... Args>
void logError(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to console and file, in cases of crashes or errors
void merge(std::string_view source); // Merges a source dumped logs into this
void clear();
private:
// Helper functions
static std::string_view moduleToString(LogModule m);
static std::string_view levelToString(LogLevel l);
};
#endif // End of header
#ifdef LOGGER_IMPL
#ifndef LOGGER_IMPL_H
#define LOGGER_IMPL_H
// Implementation
// Includes
//#include <httplib.h> // Todo : add it in the flake
#include <iostream>
#include <fstream>
#include <chrono>
/*
void NetLogger::initNetLogger(Server server) {
httplib::Client cli(server.url)
// Todo : add error handling
}
*/
template<typename... Args>
void Logger::logRAM(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
auto now = std::chrono::system_clock::now();
auto timestamp = std::format("{:%Y-%m-%d %H:%M}", now);
auto start = logBuffer.size();
fmt::format_to(
std::back_inserter(logBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(logBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(logBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
logBuffer.push_back('\n');
auto end = logBuffer.size();
lines.emplace_back(logBuffer.data() + start, end - start);
}
template<typename... Args>
void Logger::logConsole(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
std::string tempBuffer;
auto now = std::chrono::system_clock::now();
auto timestamp = std::format("{:%Y-%m-%d %H:%M}", now);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(tempBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
std::cout.write(tempBuffer.data(), tempBuffer.size());
std::cout.put('\n');
}
template<typename... Args>
void Logger::logDisk(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
// Open the logfile
std::ofstream logFile ("log.txt", std::ios::out | std::ios::app);
if (!logFile.good()) {
throw std::runtime_error("Failed to open logfile !");
}
// Create a temporary buffer
std::string tempBuffer;
auto now = std::chrono::system_clock::now();
auto timestamp = std::format("{:%Y-%m-%d %H:%M}", now);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(tempBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
logFile << tempBuffer << '\n';
logFile.close();
}
// Overload to inject a message
void Logger::logDisk(std::string_view message) {
std::ofstream logFile ("log.txt", std::ios::out | std::ios::app);
if (!logFile.good()) {
throw std::runtime_error("Failed to open logfile !");
}
logFile << message << '\n';
logFile.close();
}
template<typename... Args>
void Logger::logAll(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
// Logs to all targets !
logRAM(
module,
level,
message,
args...
);
logConsole(
module,
level,
message,
args...
);
logDisk(
module,
level,
message,
args...
);
}
template<typename... Args>
void Logger::logError(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
logDisk(
module,
level,
message,
args...
);
logConsole(
module,
level,
message,
args...
);
}
void Logger::merge(std::string_view source) {
/*
This merges a dumped logger into this one
Assumes the other logger is already formated.
This allows to add arbitrary strings into the logs
*/
logBuffer += source;
}
void Logger::clear() {
logBuffer.clear();
}
std::string_view Logger::moduleToString(LogModule m) {
using enum LogModule;
switch (m) {
case ENGINE: return "Engine";
case RENDERER: return "Renderer";
case GLFW: return "GLFW";
case CLEANUP: return "CLEANUP";
default: return "Unkown";
}
}
std::string_view Logger::levelToString(LogLevel l) {
using enum LogLevel;
switch (l) {
case EDEBUG: return "Debug";
case EINFO: return "Info";
case EINIT: return "Init";
case EWARN: return "Warn";
case EERROR: return "Error";
case EFATAL: return "Fatal";
default: return "???";
}
}
#endif
#endif