Ember
Loading...
Searching...
No Matches
Logger.cpp
Go to the documentation of this file.
1#include "Utils/Logger.h"
3#include <algorithm>
4#include <iomanip>
5#include <iostream>
6#include <sstream>
7
8#ifdef HAVE_SPDLOG
9#include <spdlog/spdlog.h>
10#endif
11
12namespace EmberCore {
13
14#ifdef HAVE_SPDLOG
15// Helper function to convert Ember LogLevel to spdlog level
16spdlog::level::level_enum ConvertToSpdlogLevel(LogLevel level) {
17 switch (level) {
18 case LogLevel::All:
19 case LogLevel::Trace:
20 return spdlog::level::trace;
21 case LogLevel::Info:
22 return spdlog::level::info;
24 return spdlog::level::warn;
25 case LogLevel::Error:
26 return spdlog::level::err;
28 return spdlog::level::critical;
29 default:
30 return spdlog::level::info;
31 }
32}
33#endif
34
35// LogEntry Implementation
37 : timestamp(std::chrono::system_clock::now()), level(lvl), category(cat), message(msg),
39
41 // Format timestamp
42 auto time_t = std::chrono::system_clock::to_time_t(timestamp);
43 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch()) % 1000;
44
45 std::stringstream ss;
46 ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
47 ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
48
49 EmberCore::String time_str = ss.str();
50
51 // Format the complete message
52 return "[" + time_str + "] [" + GetLevelString() + "] [" + category + "] " + message;
53}
54
71
73 switch (level) {
74 case LogLevel::Trace:
75 return "TRACE";
76 case LogLevel::Info:
77 return "INFO";
79 return "WARN";
80 case LogLevel::Error:
81 return "ERROR";
83 return "CRITICAL";
84 default:
85 return "UNKNOWN";
86 }
87}
88
89// Logger Implementation
91// Initialize spdlog if available
92#ifdef HAVE_SPDLOG
93 try {
94 SpdlogManager::GetInstance().Initialize();
95 } catch (const std::exception &e) {
96 // spdlog initialization failed, continue without it
97 }
98#endif
99}
100
101void Logger::Trace(const EmberCore::String &category, const EmberCore::String &message) {
102 Log(LogLevel::Trace, category, message);
103}
104
105void Logger::Info(const EmberCore::String &category, const EmberCore::String &message) {
106 Log(LogLevel::Info, category, message);
107}
108
109void Logger::Warning(const EmberCore::String &category, const EmberCore::String &message) {
110 Log(LogLevel::Warning, category, message);
111}
112
113void Logger::Error(const EmberCore::String &category, const EmberCore::String &message) {
114 Log(LogLevel::Error, category, message);
115}
116
117void Logger::Critical(const EmberCore::String &category, const EmberCore::String &message) {
118 Log(LogLevel::Critical, category, message);
119}
120
121void Logger::Log(LogLevel level, const EmberCore::String &category, const EmberCore::String &message) {
122 // Create log entry
123 auto entry = std::make_shared<LogEntry>(level, category, message);
124
125 // Add to entries list
126 entries_.push_back(entry);
127
128 // Maintain max entries limit
129 TrimEntries();
130
131 // Log to console if enabled
133#ifdef HAVE_SPDLOG
134 try {
135 auto spdlog_level = ConvertToSpdlogLevel(level);
136 // Only log if the message meets the configured log level threshold
137 if (spdlog_level >= spdlog::default_logger()->level()) {
138 spdlog::log(spdlog_level, "[{}] {}", category, message);
139 }
140 } catch (const std::exception &e) {
141 // spdlog failed, fall back to std::cout
142 std::cout << entry->FormatMessage() << std::endl;
143 }
144#else
145 std::cout << entry->FormatMessage() << std::endl;
146#endif
147 }
148
149 // Log to file if enabled
151#ifdef HAVE_SPDLOG
152 try {
153 auto spdlog_level = ConvertToSpdlogLevel(level);
154 // Only log if the message meets the configured log level threshold
155 if (spdlog_level >= spdlog::default_logger()->level()) {
156 spdlog::log(spdlog_level, "[{}] {}", category, message);
157 }
158 } catch (const std::exception &e) {
159 // spdlog failed, fall back to std::cout
160 std::cout << entry->FormatMessage() << std::endl;
161 }
162#endif
163 }
164
165 // Notify observers
167}
168
169std::vector<std::shared_ptr<LogEntry>> Logger::GetFilteredEntries(LogLevel level_filter,
170 const EmberCore::String &category_filter,
171 const EmberCore::String &search_text) const {
172
173 std::vector<std::shared_ptr<LogEntry>> filtered;
174
175 for (const auto &entry : entries_) {
176 // Filter by level - if not "All", show only exact level match
177 if (level_filter != LogLevel::All && entry->level != level_filter) {
178 continue;
179 }
180
181 // Filter by category
182 if (!category_filter.empty()) {
183 std::string entry_cat_lower = entry->category;
184 std::string filter_lower = category_filter;
185 std::transform(entry_cat_lower.begin(), entry_cat_lower.end(), entry_cat_lower.begin(), ::tolower);
186 std::transform(filter_lower.begin(), filter_lower.end(), filter_lower.begin(), ::tolower);
187
188 if (entry_cat_lower.find(filter_lower) == std::string::npos) {
189 continue;
190 }
191 }
192
193 // Filter by search text
194 if (!search_text.empty()) {
195 std::string entry_msg_lower = entry->message;
196 std::string entry_cat_lower = entry->category;
197 std::string search_lower = search_text;
198 std::transform(entry_msg_lower.begin(), entry_msg_lower.end(), entry_msg_lower.begin(), ::tolower);
199 std::transform(entry_cat_lower.begin(), entry_cat_lower.end(), entry_cat_lower.begin(), ::tolower);
200 std::transform(search_lower.begin(), search_lower.end(), search_lower.begin(), ::tolower);
201
202 if (entry_msg_lower.find(search_lower) == std::string::npos &&
203 entry_cat_lower.find(search_lower) == std::string::npos) {
204 continue;
205 }
206 }
207
208 filtered.push_back(entry);
209 }
210
211 return filtered;
212}
213
215
216Logger::ObserverId Logger::AddObserver(std::function<void()> observer) {
218 observers_[id] = observer;
219 return id;
220}
221
223
225 for (auto &pair : observers_) {
226 try {
227 pair.second();
228 } catch (const std::exception &e) {
229 // Observer failed, continue with others
230 }
231 }
232}
233
235 if (entries_.size() > max_entries_) {
236 entries_.erase(entries_.begin(), entries_.begin() + (entries_.size() - max_entries_));
237 }
238}
239
241#ifdef HAVE_SPDLOG
242 try {
243 SpdlogManager::GetInstance().SetConsoleColorsEnabled(enabled);
244 } catch (const std::exception &e) {
245 // Failed to update console colors
246 }
247#endif
248}
249
250// Static instance
252 static Logger instance;
253 return instance;
254}
255
256} // namespace EmberCore
void NotifyObservers()
Definition Logger.cpp:224
void Warning(const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:109
std::map< ObserverId, std::function< void()> > observers_
Definition Logger.h:101
void Error(const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:113
size_t max_entries_
Definition Logger.h:100
size_t ObserverId
Definition Logger.h:87
static Logger & GetInstance()
Definition Logger.cpp:251
ObserverId AddObserver(std::function< void()> observer)
Definition Logger.cpp:216
void RemoveObserver(ObserverId id)
Definition Logger.cpp:222
void Trace(const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:101
std::vector< std::shared_ptr< LogEntry > > entries_
Definition Logger.h:98
void Log(LogLevel level, const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:121
void SetConsoleColorsEnabled(bool enabled)
Definition Logger.cpp:240
bool file_logging_enabled_
Definition Logger.h:106
void ClearEntries()
Definition Logger.cpp:214
void Critical(const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:117
void Info(const EmberCore::String &category, const EmberCore::String &message)
Definition Logger.cpp:105
std::vector< std::shared_ptr< LogEntry > > GetFilteredEntries(LogLevel level_filter=LogLevel::All, const EmberCore::String &category_filter="", const EmberCore::String &search_text="") const
Definition Logger.cpp:169
bool console_logging_enabled_
Definition Logger.h:105
ObserverId next_observer_id_
Definition Logger.h:102
Main types header for EmberCore.
LogLevel
Log levels for categorizing messages.
Definition Logger.h:16
std::string String
Framework-agnostic string type.
Definition String.h:14
RGBA color with 8-bit components.
Definition Color.h:10
static const Color Yellow
Definition Color.h:49
static const Color Gray
Definition Color.h:52
static const Color Magenta
Definition Color.h:51
static const Color Red
Definition Color.h:46
static const Color White
Definition Color.h:45
EmberCore::Color GetLevelColor() const
Definition Logger.cpp:55
EmberCore::String FormatMessage() const
Definition Logger.cpp:40
std::chrono::system_clock::time_point timestamp
Definition Logger.h:29
EmberCore::String GetLevelString() const
Definition Logger.cpp:72
LogLevel level
Definition Logger.h:30
LogEntry(LogLevel lvl, const EmberCore::String &cat, const EmberCore::String &msg)
Definition Logger.cpp:36
EmberCore::String category
Definition Logger.h:31
EmberCore::String message
Definition Logger.h:32
EmberCore::String formatted_message
Definition Logger.h:33