#pragma once #include #include #include #include #include #include #include #include #include #include class Logger { public: static Logger& Get() { static Logger instance; return instance; } Logger(Logger const&) = delete; void operator=(Logger const&) = delete; enum class LogLevel { Info, Warning, Error, Shutdown, Initialize, Update, Render, Input, Physics, Audio, Network, Scripting, AI, Resource, Memory, Debug, Count // Do not use this, it's just to get the number of log levels it must at the end }; // Return the size of the enum class LogLevel as a constant integer static constexpr int LogLevelCount = static_cast(LogLevel::Count); struct LogEntry { std::string message; LogLevel level; }; struct LogLevelInfo { const char* name; int value; ImVec4 color; }; static const LogLevelInfo GetLogLevelInfo(LogLevel level) { switch (level) { case LogLevel::Info: return LogLevelInfo{ "Info", 0, ImVec4(0.0f, 1.0f, 0.0f, 1.0f) }; case LogLevel::Warning: return LogLevelInfo{ "Warning", 1, ImVec4(1.0f, 1.0f, 0.0f, 1.0f) }; case LogLevel::Error: return LogLevelInfo{ "Error", 2, ImVec4(1.0f, 0.0f, 0.0f, 1.0f) }; case LogLevel::Shutdown: return LogLevelInfo{ "Shutdown", 3, ImVec4(0.5f, 0.0f, 0.0f, 1.0f) }; case LogLevel::Initialize: return LogLevelInfo{ "Initialize", 4, ImVec4(0.0f, 1.0f, 1.0f, 1.0f) }; case LogLevel::Update: return LogLevelInfo{ "Update", 5, ImVec4(1.0f, 0.0f, 1.0f, 1.0f) }; case LogLevel::Render: return LogLevelInfo{ "Render", 6, ImVec4(1.0f, 1.0f, 1.0f, 1.0f) }; case LogLevel::Input: return LogLevelInfo{ "Input", 7, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Physics: return LogLevelInfo{ "Physics", 8, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Audio: return LogLevelInfo{ "Audio", 9, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Network: return LogLevelInfo{ "Network", 10, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Scripting: return LogLevelInfo{ "Scripting", 11, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::AI: return LogLevelInfo{ "AI", 12, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Resource: return LogLevelInfo{ "Resource", 13, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Memory: return LogLevelInfo{ "Memory", 14, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; case LogLevel::Debug: return LogLevelInfo{ "Debug", 15, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) }; default: return LogLevelInfo{ "Unknown", 16, ImVec4(1.0f, 1.0f, 1.0f, 1.0f) }; } } Logger() { char* appdata = nullptr; size_t len; _dupenv_s(&appdata, &len, "APPDATA"); if (appdata == nullptr) { m_appdataPath = "log.log"; } else { m_appdataPath = appdata; } free(appdata); std::string directoryPath = m_appdataPath + "\\Khaotic Engine"; CreateDirectoryA(directoryPath.c_str(), NULL); ManageLogFiles(directoryPath); m_logFilePath = directoryPath + "\\" + m_logFileName; // Enable only the Error warning and shutdown log levels for (int i = 0; i < LogLevelCount; i++) { m_disabledLogLevels[i] = true; if (i == static_cast(LogLevel::Error) || i == static_cast(LogLevel::Warning) || i == static_cast(LogLevel::Shutdown)) { m_disabledLogLevels[i] = false; } } } // ecrit un message dans le fichier de log et le stocke dans le buffer void Log(const std::string& message, const std::string& fileName, int lineNumber, LogLevel level = LogLevel::Info) { auto now = std::chrono::system_clock::now(); auto in_time_t = std::chrono::system_clock::to_time_t(now); std::tm buf; localtime_s(&buf, &in_time_t); // Obtenez les millisecondes à partir de maintenant auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; // Utilisez LogLevelToString pour obtenir la chaîne de caractères du niveau de log std::string levelStr = GetLogLevelInfo(level).name; std::stringstream ss; ss << "[" << std::put_time(&buf, "%Y-%m-%d") << "] " << "[" << std::put_time(&buf, "%X") << "." << std::setfill('0') << std::setw(3) << ms.count() << "] " << "[" << levelStr << "] " << "[" << fileName << ":" << lineNumber << "] " << message; Log(ss.str(), level); std::ofstream file(m_logFilePath, std::ios::app); if (file.is_open()) { file << ss.str() << std::endl; file.close(); } } // ecrit un message dans la console void Log(const std::string& message, LogLevel level) { // Si le niveau de log est désactivé, ne faites rien if (m_disabledLogLevels[GetLogLevelInfo(level).value]) { return; } if (logBuffer.size() >= logBufferSize) { logBuffer.pop_front(); } logBuffer.push_back({ message, level }); } const std::deque& GetLogBuffer() const { return logBuffer; } void ManageLogFiles(const std::string& directoryPath) { std::vector logFiles; // Parcourez tous les fichiers dans le dossier for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) { // Si le fichier est un fichier de log, ajoutez-le à la liste if (entry.path().extension() == ".log") { logFiles.push_back(entry.path()); } } // Si nous avons plus de trois fichiers de log, supprimez le plus ancien while (logFiles.size() >= 3) { // Triez les fichiers par date de modification, le plus ancien en premier std::sort(logFiles.begin(), logFiles.end(), [](const std::filesystem::path& a, const std::filesystem::path& b) { return std::filesystem::last_write_time(a) < std::filesystem::last_write_time(b); }); // Supprimez le fichier le plus ancien std::filesystem::remove(logFiles[0]); // Supprimez-le de la liste logFiles.erase(logFiles.begin()); } // Créez un nouveau fichier de log pour cette exécution auto now = std::chrono::system_clock::now(); auto in_time_t = std::chrono::system_clock::to_time_t(now); std::tm buf; localtime_s(&buf, &in_time_t); std::stringstream ss; ss << "Khaotic_log_" << std::put_time(&buf, "%Y_%m_%d_%Hh%Mm%Ss") << ".log"; m_logFileName = ss.str(); } bool m_disabledLogLevels[LogLevelCount]; std::string m_logFilePath; private: std::string m_filename; std::string m_appdataPath; std::string m_logFileName; std::deque logBuffer; const size_t logBufferSize = 100; };