Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
system_utils.h
Go to the documentation of this file.
1#pragma once
2
3// "system_utils.h" -> simplified logging implementation
4// Centralized logger that duplicates output to std::cout, std::clog, to a file (olympe.log)
5// and to the UI log window. Use:
6// Logging::InitLogger();
7// SYSTEM_LOG << "Hello" << std::endl;
8
9#include <streambuf>
10#include <ostream>
11#include <vector>
12#include <memory>
13#include <fstream>
14#include <mutex>
15#include <iostream>
16#include <string>
17#include <sstream>
18#include "system_consts.h"
19#include "log_sink.h"
20
21//-------------------------------------------------------------
22// Convenience macro (keeps existing code using SYSTEM_LOG)
23#define SYSTEM_LOG ::Logging::Logger()
24
25namespace Logging
26{
27 // Output destinations flags
28 enum Outputs : unsigned
29 {
30 Out_Cout = 1u << 0,
31 Out_Clog = 1u << 1,
32 Out_File = 1u << 2,
33 Out_Panel = 1u << 3
34 };
35
36 // Simple line-buffering logger with operator<< overloads
37 class Log
38 {
39 public:
41
42 // Initialize file logging (optional). Safe to call multiple times.
43 bool Init(const std::string& filename = "olympe.log")
44 {
45 std::lock_guard<std::mutex> lock(m_);
46 if (file_open_) return true;
47 file_.open(filename.c_str(), std::ios::app);
48 if (file_.is_open()) file_open_ = true;
49 // ensure panel sink exists (log_sink handles buffering until UI attached)
50 return true;
51 }
52
53 void Shutdown()
54 {
55 std::lock_guard<std::mutex> lock(m_);
56 if (file_.is_open()) { file_.flush(); file_.close(); }
57 file_open_ = false;
58 }
59
60 void SetOutputs(unsigned flags)
61 {
62 std::lock_guard<std::mutex> lock(m_);
64 }
65
66 unsigned GetOutputs() const { return outputs_; }
67
68 // Generic stream insertion
69 template<typename T>
70 auto operator<<(const T& v) -> decltype(std::declval<std::ostringstream&>() << v, std::declval<Log&>())
71 {
72 {
73 std::lock_guard<std::mutex> lock(m_);
74 buffer_ << v;
75 }
77 return *this;
78 }
79
80 // Manipulators like std::endl
81 using Manip = std::ostream& (*)(std::ostream&);
83 {
84 if (m == static_cast<Manip>(&std::endl))
85 {
86 // endl inserts newline and flushes
87 {
88 std::lock_guard<std::mutex> lock(m_);
89 buffer_ << m;
90 }
93 }
94 else if (m == static_cast<Manip>(&std::flush))
95 {
97 }
98 else
99 {
100 // other manipulators forward into buffer
101 std::lock_guard<std::mutex> lock(m_);
102 buffer_ << m;
103 }
104 return *this;
105 }
106
107 private:
108 void writeToOutputs(const std::string& s)
109 {
110 // write to each enabled output (no duplication)
111 if (outputs_ & Out_Cout) {
112 std::cout << s;
113 std::cout.flush();
114 }
115 /*if (outputs_ & Out_Clog) {
116 std::clog << s;
117 std::clog.flush();
118 }/**/
119 if ((outputs_ & Out_File) && file_open_) {
120 file_ << s;
121 file_.flush();
122 }
123 if (outputs_ & Out_Panel) {
124 // send to UI log sink (thread-safe buffered)
126 }
127 }
128
130 {
131 std::lock_guard<std::mutex> lock(m_);
132 std::string s = buffer_.str();
133 size_t pos = 0;
134 while ((pos = s.find('\n')) != std::string::npos)
135 {
136 std::string line = s.substr(0, pos + 1);
138 s.erase(0, pos + 1);
139 }
140 buffer_.str(""); buffer_.clear();
141 buffer_ << s;
142 }
143
145 {
146 std::lock_guard<std::mutex> lock(m_);
147 std::string s = buffer_.str();
148 if (!s.empty())
149 {
151 buffer_.str(""); buffer_.clear();
152 }
153 }
154
155 private:
156 mutable std::mutex m_;
157 std::ostringstream buffer_;
158 unsigned outputs_;
159 std::ofstream file_;
161 };
162
163 // Access global logger instance
164 inline Log& Logger()
165 {
166 static Log s_logger;
167 return s_logger;
168 }
169
170 // Convenience init/shutdown
171 inline bool InitLogger(const std::string& filename = "olympe.log")
172 {
173 bool res = Logger().Init(filename);
174 // enable file output only if file opened
175 if (!Logger().GetOutputs()) {}
176 // by default, keep cout, clog and panel enabled; file enabled if opened
177 return res;
178 }
179
180 inline void ShutdownLogger()
181 {
182 Logger().Shutdown();
183 }
184}
185
186
187//-------------------------------------------------------------
188// JSON helpers (kept here for compatibility with existing code)
189//
190static std::string escape_json_string(const std::string& s)
191{
192 std::string out;
193 out.reserve(s.size() + 4);
194 for (char c : s)
195 {
196 switch (c)
197 {
198 case '\\': out += "\\\\"; break;
199 case '"': out += "\\\""; break;
200 case '\b': out += "\\b"; break;
201 case '\f': out += "\\f"; break;
202 case '\n': out += "\\n"; break;
203 case '\r': out += "\\r"; break;
204 case '\t': out += "\\t"; break;
205 default: out += c; break;
206 }
207 }
208 return out;
209}
210//-------------------------------------------------------------
211static bool extract_json_string(const std::string& json, const std::string& key, std::string& out)
212{
213 size_t pos = json.find('"' + key + '"');
214 if (pos == std::string::npos) pos = json.find(key);
215 if (pos == std::string::npos) return false;
216 pos = json.find(':', pos);
217 if (pos == std::string::npos) return false;
218 ++pos;
219 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
220 if (pos < json.size() && json[pos] == '"') ++pos;
221 size_t start = pos;
222 while (pos < json.size() && json[pos] != '"' && json[pos] != '\n' && json[pos] != '\r') ++pos;
223 if (pos <= start) return false;
224 out = json.substr(start, pos - start);
225 return true;
226}
227//-------------------------------------------------------------
228static bool extract_json_double(const std::string& json, const std::string& key, double& out)
229{
230 size_t pos = json.find('"' + key + '"');
231 if (pos == std::string::npos) pos = json.find(key);
232 if (pos == std::string::npos) return false;
233 pos = json.find(':', pos);
234 if (pos == std::string::npos) return false;
235 ++pos;
236 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
237 size_t start = pos;
238 while (pos < json.size() && (isdigit(static_cast<unsigned char>(json[pos])) || json[pos] == '+' || json[pos] == '-' || json[pos] == '.' || json[pos] == 'e' || json[pos] == 'E')) ++pos;
239 if (pos <= start) return false;
240 try { out = std::stod(json.substr(start, pos - start)); return true; }
241 catch (...) { return false; }
242}
243//-------------------------------------------------------------
244static bool extract_json_int(const std::string& json, const std::string& key, int& out)
245{
246 double d;
247 if (!extract_json_double(json, key, d)) return false;
248 out = static_cast<int>(d);
249 return true;
250}
251//-------------------------------------------------------------
252static bool extract_json_bool(const std::string& json, const std::string& key, bool& out)
253{
254 size_t pos = json.find('"' + key + '"');
255 if (pos == std::string::npos) pos = json.find(key);
256 if (pos == std::string::npos) return false;
257 pos = json.find(':', pos);
258 if (pos == std::string::npos) return false;
259 ++pos;
260 while (pos < json.size() && isspace(static_cast<unsigned char>(json[pos]))) ++pos;
261 if (json.compare(pos, 4, "true") == 0) { out = true; return true; }
262 if (json.compare(pos, 5, "false") == 0) { out = false; return true; }
263 return false;
264}
265
266//-------------------------------------------------------------
267// Load configuration from JSON file (keeps previous behavior)
268void LoadOlympeConfig(const char* filename);
269//-------------------------------------------------------------
nlohmann::json json
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::ostream &(*)(std::ostream &) Manip
unsigned outputs_
std::ostringstream buffer_
unsigned GetOutputs() const
void SetOutputs(unsigned flags)
std::mutex m_
void Shutdown()
Log & operator<<(Manip m)
void flushCompleteLinesIfAny()
void writeToOutputs(const std::string &s)
auto operator<<(const T &v) -> decltype(std::declval< std::ostringstream & >()<< v, std::declval< Log & >())
bool Init(const std::string &filename="olympe.log")
void flushRemaining()
std::ofstream file_
bool InitLogger(const std::string &filename="olympe.log")
void ShutdownLogger()
Log & Logger()
void AppendToLogWindow(const std::string &text)
void LoadOlympeConfig(const char *filename)
static std::string escape_json_string(const std::string &s)
static bool extract_json_double(const std::string &json, const std::string &key, double &out)
static bool extract_json_bool(const std::string &json, const std::string &key, bool &out)
static bool extract_json_int(const std::string &json, const std::string &key, int &out)
static bool extract_json_string(const std::string &json, const std::string &key, std::string &out)