Khaotic Engine Reborn
Loading...
Searching...
No Matches
Logger.h
1#pragma once
2#include <fstream>
3#include <string>
4#include <Windows.h>
5#include <chrono>
6#include <iomanip>
7#include <sstream>
8#include <filesystem>
9#include <deque>
10#include <unordered_set>
11#include <imgui.h>
12
13class Logger
14{
15public:
20 static Logger& Get()
21 {
22 static Logger instance;
23 return instance;
24 }
25
29 Logger(Logger const&) = delete;
30 void operator=(Logger const&) = delete;
31
37 enum class LogLevel
38 {
39 Info,
40 Warning,
41 Error,
42 Shutdown,
43 Initialize,
44 Update,
45 Render,
46 Input,
47 Physics,
48 Audio,
49 Network,
50 Scripting,
51 AI,
52 Resource,
53 Memory,
54 Debug,
55 Count // Do not use this, it's just to get the number of log levels it must at the end
56 };
57
58 // Return the size of the enum class LogLevel as a constant integer
59 static constexpr int LogLevelCount = static_cast<int>(LogLevel::Count);
60
65 struct LogEntry
66 {
67 std::string message;
68 LogLevel level;
69 };
70
76 {
77 const char* name;
78 int value;
79 ImVec4 color;
80 };
81
89 {
90 switch (level)
91 {
92 case LogLevel::Info: return LogLevelInfo{ "Info", 0, ImVec4(0.0f, 1.0f, 0.0f, 1.0f) };
93 case LogLevel::Warning: return LogLevelInfo{ "Warning", 1, ImVec4(1.0f, 1.0f, 0.0f, 1.0f) };
94 case LogLevel::Error: return LogLevelInfo{ "Error", 2, ImVec4(1.0f, 0.0f, 0.0f, 1.0f) };
95 case LogLevel::Shutdown: return LogLevelInfo{ "shutdown", 3, ImVec4(0.5f, 0.0f, 0.0f, 1.0f) };
96 case LogLevel::Initialize: return LogLevelInfo{ "initialize", 4, ImVec4(0.0f, 1.0f, 1.0f, 1.0f) };
97 case LogLevel::Update: return LogLevelInfo{ "Update", 5, ImVec4(1.0f, 0.0f, 1.0f, 1.0f) };
98 case LogLevel::Render: return LogLevelInfo{ "render", 6, ImVec4(1.0f, 1.0f, 1.0f, 1.0f) };
99 case LogLevel::Input: return LogLevelInfo{ "Input", 7, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
100 case LogLevel::Physics: return LogLevelInfo{ "physics", 8, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
101 case LogLevel::Audio: return LogLevelInfo{ "Audio", 9, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
102 case LogLevel::Network: return LogLevelInfo{ "Network", 10, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
103 case LogLevel::Scripting: return LogLevelInfo{ "Scripting", 11, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
104 case LogLevel::AI: return LogLevelInfo{ "AI", 12, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
105 case LogLevel::Resource: return LogLevelInfo{ "Resource", 13, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
106 case LogLevel::Memory: return LogLevelInfo{ "Memory", 14, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
107 case LogLevel::Debug: return LogLevelInfo{ "Debug", 15, ImVec4(0.5f, 0.5f, 0.5f, 1.0f) };
108 default: return LogLevelInfo{ "Unknown", 16, ImVec4(1.0f, 1.0f, 1.0f, 1.0f) };
109 }
110 }
111
117 {
118 char* appdata = nullptr;
119 size_t len;
120 _dupenv_s(&appdata, &len, "APPDATA");
121 if (appdata == nullptr)
122 {
123 m_appdataPath = "log.log";
124 }
125 else
126 {
127 m_appdataPath = appdata;
128 }
129 free(appdata);
130 std::string directoryPath = m_appdataPath + "\\Khaotic Engine";
131 CreateDirectoryA(directoryPath.c_str(), NULL);
132
133 ManageLogFiles(directoryPath);
134
135 m_logFilePath = directoryPath + "\\" + m_logFileName;
136
137 // Enable only the Error warning and shutdown log levels
138 for (int i = 0; i < LogLevelCount; i++)
139 {
140 m_disabledLogLevels[i] = true;
141
142 if (i == static_cast<int>(LogLevel::Error) || i == static_cast<int>(LogLevel::Warning) || i == static_cast<int>(LogLevel::Shutdown))
143 {
144 m_disabledLogLevels[i] = false;
145
146 }
147 }
148
149 }
150
158 void Log(const std::string& message, const std::string& fileName, int lineNumber, LogLevel level = LogLevel::Info)
159 {
160
161 auto now = std::chrono::system_clock::now();
162 auto in_time_t = std::chrono::system_clock::to_time_t(now);
163
164 std::tm buf;
165 localtime_s(&buf, &in_time_t);
166
167 // Obtenez les millisecondes à partir de maintenant
168 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
169
170 // Utilisez LogLevelToString pour obtenir la chaîne de caractères du niveau de log
171 std::string levelStr = GetLogLevelInfo(level).name;
172
173 std::stringstream ss;
174 ss << "[" << std::put_time(&buf, "%Y-%m-%d") << "] "
175 << "[" << std::put_time(&buf, "%X") << "." << std::setfill('0') << std::setw(3) << ms.count() << "] "
176 << "[" << levelStr << "] "
177 << "[" << fileName << ":" << lineNumber << "] "
178 << message;
179
180 Log(ss.str(), level);
181
182 std::ofstream file(m_logFilePath, std::ios::app);
183 if (file.is_open())
184 {
185 file << ss.str() << std::endl;
186 file.close();
187 }
188 }
189
200 void Log(const std::string& message, LogLevel level)
201 {
202
203 // Si le niveau de log est désactivé, ne faites rien
204 if (m_disabledLogLevels[GetLogLevelInfo(level).value])
205 {
206 return;
207 }
208
209 if (logBuffer.size() >= logBufferSize)
210 {
211 logBuffer.pop_front();
212 }
213 logBuffer.push_back({ message, level });
214 }
215
220 const std::deque<LogEntry>& GetLogBuffer() const { return logBuffer; }
221
230 void ManageLogFiles(const std::string& directoryPath)
231 {
232 std::vector<std::filesystem::path> logFiles;
233
234 // Parcourez tous les fichiers dans le dossier
235 for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
236 {
237 // Si le fichier est un fichier de log, ajoutez-le à la liste
238 if (entry.path().extension() == ".log")
239 {
240 logFiles.push_back(entry.path());
241 }
242 }
243
244 // Si nous avons plus de trois fichiers de log, supprimez le plus ancien
245 while (logFiles.size() >= 3)
246 {
247 // Triez les fichiers par date de modification, le plus ancien en premier
248 std::sort(logFiles.begin(), logFiles.end(), [](const std::filesystem::path& a, const std::filesystem::path& b)
249 {
250 return std::filesystem::last_write_time(a) < std::filesystem::last_write_time(b);
251 });
252
253 // Supprimez le fichier le plus ancien
254 std::filesystem::remove(logFiles[0]);
255
256 // Supprimez-le de la liste
257 logFiles.erase(logFiles.begin());
258 }
259
260 // Créez un nouveau fichier de log pour cette exécution
261 auto now = std::chrono::system_clock::now();
262 auto in_time_t = std::chrono::system_clock::to_time_t(now);
263 std::tm buf;
264 localtime_s(&buf, &in_time_t);
265
266 std::stringstream ss;
267 ss << "Khaotic_log_" << std::put_time(&buf, "%Y_%m_%d_%Hh%Mm%Ss") << ".log";
268 m_logFileName = ss.str();
269 }
270
271 bool m_disabledLogLevels[LogLevelCount];
272 std::string m_logFilePath;
273
274private:
275 std::string m_filename;
276 std::string m_appdataPath;
277 std::string m_logFileName;
278
279 std::deque<LogEntry> logBuffer;
280 const size_t logBufferSize = 100;
281
282};
static Logger & Get()
Definition Logger.h:20
Logger(Logger const &)=delete
const std::deque< LogEntry > & GetLogBuffer() const
Definition Logger.h:220
static const LogLevelInfo GetLogLevelInfo(LogLevel level)
Definition Logger.h:88
void ManageLogFiles(const std::string &directoryPath)
Definition Logger.h:230
void Log(const std::string &message, const std::string &fileName, int lineNumber, LogLevel level=LogLevel::Info)
Definition Logger.h:158
Logger()
Definition Logger.h:116
LogLevel
Definition Logger.h:38
void Log(const std::string &message, LogLevel level)
Definition Logger.h:200
Definition Logger.h:66