DotNameLib
Loading...
Searching...
No Matches
ConsoleLogger.hpp
Go to the documentation of this file.
1#ifndef CONSOLELOGGER_HPP
2#define CONSOLELOGGER_HPP
3
4#include "ILogger.hpp"
5
6#include <chrono>
7#include <fstream>
8#include <iomanip>
9#include <iostream>
10#include <map>
11#include <mutex>
12#include <sstream>
13#include <string>
14#include <utility>
15
16#include "fmt/core.h"
17
18#ifdef _WIN32
20#include <io.h>
21#define isatty _isatty
22#define fileno _fileno
23#else
24#include <unistd.h>
25#endif
26
28private:
29 std::mutex logMutex_;
30 std::ofstream logFile_;
31 bool addNewLine_ = true;
32 std::string appPrefix_;
33
38#ifdef DEBUG
40#else
42#endif
43
44 bool colorEnabled_ = true; // User can override
45 bool autoDetectColor_ = true; // Auto-detect TTY support
46
47public:
48 ConsoleLogger() = default;
50 std::lock_guard<std::mutex> lock(logMutex_);
51 if (logFile_.is_open()) {
52 logFile_.close();
53 }
54 }
55
56 ConsoleLogger(const ConsoleLogger &) = delete;
58 ConsoleLogger(ConsoleLogger &&other) noexcept
59 : logFile_(std::move(other.logFile_)), addNewLine_(other.addNewLine_),
60 appPrefix_(std::move(other.appPrefix_)), currentLevel_(other.currentLevel_),
61 colorEnabled_(other.colorEnabled_), autoDetectColor_(other.autoDetectColor_) {}
62
64 if (this != &other) {
65 // Use std::lock to avoid deadlocks
66 std::lock(logMutex_, other.logMutex_);
67 std::lock_guard<std::mutex> lock1(logMutex_, std::adopt_lock);
68 std::lock_guard<std::mutex> lock2(other.logMutex_, std::adopt_lock);
69
70 logFile_ = std::move(other.logFile_);
71 addNewLine_ = other.addNewLine_;
72 appPrefix_ = std::move(other.appPrefix_);
73 currentLevel_ = other.currentLevel_;
74 colorEnabled_ = other.colorEnabled_;
75 autoDetectColor_ = other.autoDetectColor_;
76 }
77 return *this;
78 }
79
80 void debug(const std::string &message, const std::string &caller = "") override {
82 };
83
84 void info(const std::string &message, const std::string &caller = "") override {
86 };
87
88 void warning(const std::string &message, const std::string &caller = "") override {
90 };
91
92 void error(const std::string &message, const std::string &caller = "") override {
94 };
95
96 void critical(const std::string &message, const std::string &caller = "") override {
98 };
99
107 void log(dotnamecpp::logging::Level level, const std::string &message,
108 const std::string &caller) {
109 std::lock_guard<std::mutex> lock(logMutex_);
110
111 // Get current time
112 auto now = std::chrono::system_clock::now();
113 std::time_t now_c = std::chrono::system_clock::to_time_t(now);
114 std::tm now_tm;
115
116 // Windows and POSIX have different thread-safe localtime functions
117#ifdef _WIN32
118 localtime_s(&now_tm, &now_c);
119#else
120 localtime_r(&now_c, &now_tm);
121#endif
122
123 // Create log header
124 std::ostringstream header;
125 if (!appPrefix_.empty()) {
126 header << "[" << appPrefix_ << "]";
127 }
128 header << "[" << std::put_time(&now_tm, "%Y-%m-%d %H:%M:%S") << "]";
129 header << "[" << levelToString(level) << "]";
130 if (!caller.empty()) {
131 header << "[" << caller << "]";
132 }
133 header << " ";
134
135 // Log to console
136 if (shouldUseColors()) {
137 setConsoleColor(level);
138 }
139 std::cout << header.str() << message;
140 if (addNewLine_) {
141 std::cout << "\n";
142 }
143
144 if (shouldUseColors()) {
146 }
147
148 // Log to file if enabled
149 if (logFile_.is_open()) {
150 logFile_ << header.str() << message;
151 if (addNewLine_) {
152 logFile_ << "\n";
153 }
154 }
155 };
156
158 std::lock_guard<std::mutex> lock(logMutex_);
159 currentLevel_ = level;
160 };
161
162 [[nodiscard]]
164 return currentLevel_;
165 };
166
167 void setAppPrefix(const std::string &prefix) override {
168 std::lock_guard<std::mutex> lock(logMutex_);
169 appPrefix_ = prefix;
170 };
171
172 [[nodiscard]]
173 std::string getAppPrefix() const override {
174 return appPrefix_;
175 };
176
177 bool enableFileLogging(const std::string &filename) override {
178 std::lock_guard<std::mutex> lock(logMutex_);
179 try {
180 logFile_.open(filename, std::ios::out | std::ios::app);
181 return logFile_.is_open();
182 } catch (const std::ios_base::failure &e) {
183 std::cerr << "Failed to open log file: " << filename << " - " << e.what() << "\n";
184 return false;
185 } catch (const std::exception &e) {
186 std::cerr << "Failed to open log file: " << filename << " - " << e.what() << "\n";
187 return false;
188 } catch (...) {
189 std::cerr << "Failed to open log file: " << filename << "\n";
190 return false;
191 }
192 };
193
194 void disableFileLogging() override {
195 std::lock_guard<std::mutex> lock(logMutex_);
196 if (logFile_.is_open()) {
197 logFile_.close();
198 }
199 };
200
207 static std::string levelToString(dotnamecpp::logging::Level level) {
208 switch (level) {
209 case dotnamecpp::logging::Level::LOG_DEBUG: return "DBG";
210 case dotnamecpp::logging::Level::LOG_INFO: return "INF";
212 case dotnamecpp::logging::Level::LOG_ERROR: return "ERR";
214 default: return "INF";
215 }
216 }
217
222 static void resetConsoleColor() {
223#ifdef _WIN32
224 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
225 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
226#elif defined(__EMSCRIPTEN__)
227// no colors, no reset
228#else
229 std::cout << "\033[0m";
230#endif
231 }
232
233#ifdef _WIN32
234 static void setConsoleColorWindows(dotnamecpp::logging::Level level) {
235 const std::map<dotnamecpp::logging::Level, WORD> colorMap = {
237 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY},
238 {dotnamecpp::logging::Level::LOG_INFO, FOREGROUND_GREEN | FOREGROUND_INTENSITY},
240 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY},
241 {dotnamecpp::logging::Level::LOG_ERROR, FOREGROUND_RED | FOREGROUND_INTENSITY},
243 FOREGROUND_RED | FOREGROUND_INTENSITY | FOREGROUND_BLUE }};
244 auto it = colorMap.find(level);
245 if (it != colorMap.end()) {
246 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), it->second);
247 } else {
249 }
250 }
251#else
253 static const std::map<dotnamecpp::logging::Level, const char *> colorMap = {
259 auto it = colorMap.find(level);
260 if (it != colorMap.end()) {
261 std::cout << it->second;
262 } else {
264 }
265 }
266#endif
267
269#ifdef _WIN32
270 setConsoleColorWindows(level);
271#elif EMSCRIPTEN
272 // no colors
273#else
274 setConsoleColorUnix(level);
275#endif
276 }
277
278private:
279 std::string headerName_ = "DotNameLib";
280 bool includeName_ = true;
281 bool includeTime_ = true;
282 bool includeCaller_ = true;
283 bool includeLevel_ = true;
284
294 void logToStream(std::ostream &stream, dotnamecpp::logging::Level level,
295 const std::string &message, const std::string &caller, const std::tm &now_tm) {
296 setConsoleColor(level);
297 stream << buildHeader(now_tm, caller, level) << message;
299 if (addNewLine_) {
300 stream << "\n";
301 }
302 // Explicitly flush the stream to ensure immediate output
303 stream.flush();
304 }
305
314 std::string buildHeader(const std::tm &now_tm, const std::string &caller,
315 dotnamecpp::logging::Level level) const {
316 std::ostringstream header;
317 if (includeName_) {
318 header << "[" << headerName_ << "] ";
319 }
320 if (includeTime_) {
321 header << "[" << std::put_time(&now_tm, "%d-%m-%Y %H:%M:%S") << "] ";
322 }
323 if (includeCaller_ && !caller.empty()) {
324 header << "[" << caller << "] ";
325 }
326 if (includeLevel_) {
327 header << "[" << levelToString(level) << "] ";
328 }
329 return header.str();
330 }
331
332public:
338 void setHeaderName(const std::string &headerName) {
339 std::lock_guard<std::mutex> lock(logMutex_);
340 headerName_ = headerName;
341 }
342
348 void showHeaderName(bool includeName) {
349 std::lock_guard<std::mutex> lock(logMutex_);
350 includeName_ = includeName;
351 }
352
358 void showHeaderTime(bool includeTime) {
359 std::lock_guard<std::mutex> lock(logMutex_);
360 includeTime_ = includeTime;
361 }
362
368 void showHeaderCaller(bool includeCaller) {
369 std::lock_guard<std::mutex> lock(logMutex_);
370 includeCaller_ = includeCaller;
371 }
372
378 void showHeaderLevel(bool includeLevel) {
379 std::lock_guard<std::mutex> lock(logMutex_);
380 includeLevel_ = includeLevel;
381 }
382
388 void noHeader(bool noHeader) {
389 if (noHeader) {
390 showHeaderName(false);
391 showHeaderTime(false);
392 showHeaderCaller(false);
393 showHeaderLevel(false);
394 } else {
395 showHeaderName(true);
396 showHeaderTime(true);
397 showHeaderCaller(true);
398 showHeaderLevel(true);
399 }
400 }
401
410 void visibleHeaders(bool incName, bool incTime, bool incCaller, bool incLevel) {
411 showHeaderName(incName);
412 showHeaderTime(incTime);
413 showHeaderCaller(incCaller);
414 showHeaderLevel(incLevel);
415 }
416
422 void setColorEnabled(bool enabled) {
423 std::lock_guard<std::mutex> lock(logMutex_);
424 colorEnabled_ = enabled;
425 autoDetectColor_ = false; // Manual override disables auto-detection
426 }
427
433 void setAutoDetectColor(bool autoDetect) {
434 std::lock_guard<std::mutex> lock(logMutex_);
435 autoDetectColor_ = autoDetect;
436 }
437
438private:
444 bool shouldUseColors() const {
445 if (!autoDetectColor_) {
446 return colorEnabled_;
447 }
448 // Auto-detect: check if stdout is a TTY
449#ifdef __EMSCRIPTEN__
450 return false; // No color support in Emscripten
451#else
452 return colorEnabled_ && (isatty(fileno(stdout)) != 0);
453#endif
454 }
455}; // class ConsoleLogger
456
457#endif
void showHeaderTime(bool includeTime)
Show or hide the header time in the log output.
Definition ConsoleLogger.hpp:358
ConsoleLogger & operator=(ConsoleLogger &&other) noexcept
Definition ConsoleLogger.hpp:63
dotnamecpp::logging::Level getLevel() const override
Get the Level object.
Definition ConsoleLogger.hpp:163
~ConsoleLogger()
Definition ConsoleLogger.hpp:49
void setLevel(dotnamecpp::logging::Level level) override
Set the Level object.
Definition ConsoleLogger.hpp:157
void setAppPrefix(const std::string &prefix) override
Set the application prefix for log messages.
Definition ConsoleLogger.hpp:167
static std::string levelToString(dotnamecpp::logging::Level level)
Convert a logging level to its string representation.
Definition ConsoleLogger.hpp:207
void showHeaderName(bool includeName)
Show or hide the header name in the log output.
Definition ConsoleLogger.hpp:348
void noHeader(bool noHeader)
Show or hide all headers in the log output.
Definition ConsoleLogger.hpp:388
static void resetConsoleColor()
Reset the console color to default.
Definition ConsoleLogger.hpp:222
void warning(const std::string &message, const std::string &caller="") override
Log a warning message.
Definition ConsoleLogger.hpp:88
static void setConsoleColorUnix(dotnamecpp::logging::Level level)
Definition ConsoleLogger.hpp:252
ConsoleLogger(ConsoleLogger &&other) noexcept
Definition ConsoleLogger.hpp:58
void debug(const std::string &message, const std::string &caller="") override
Log a debug message.
Definition ConsoleLogger.hpp:80
void error(const std::string &message, const std::string &caller="") override
Log an error message.
Definition ConsoleLogger.hpp:92
ConsoleLogger & operator=(const ConsoleLogger &)=delete
void disableFileLogging() override
Disable logging to a file.
Definition ConsoleLogger.hpp:194
void showHeaderLevel(bool includeLevel)
Show or hide the header level in the log output.
Definition ConsoleLogger.hpp:378
std::string getAppPrefix() const override
Get the App Prefix object.
Definition ConsoleLogger.hpp:173
void log(dotnamecpp::logging::Level level, const std::string &message, const std::string &caller)
Logs a message with a specified level to the console and optionally to a file.
Definition ConsoleLogger.hpp:107
void info(const std::string &message, const std::string &caller="") override
Log an info message.
Definition ConsoleLogger.hpp:84
bool enableFileLogging(const std::string &filename) override
Enable logging to a file.
Definition ConsoleLogger.hpp:177
void showHeaderCaller(bool includeCaller)
Show or hide the header caller in the log output.
Definition ConsoleLogger.hpp:368
void setHeaderName(const std::string &headerName)
Set the Header Name object.
Definition ConsoleLogger.hpp:338
void critical(const std::string &message, const std::string &caller="") override
Log a critical message.
Definition ConsoleLogger.hpp:96
ConsoleLogger()=default
void setAutoDetectColor(bool autoDetect)
Enable automatic color detection based on TTY.
Definition ConsoleLogger.hpp:433
void visibleHeaders(bool incName, bool incTime, bool incCaller, bool incLevel)
Show or hide specific headers in the log output.
Definition ConsoleLogger.hpp:410
void setColorEnabled(bool enabled)
Enable or disable colored output.
Definition ConsoleLogger.hpp:422
static void setConsoleColor(dotnamecpp::logging::Level level)
Definition ConsoleLogger.hpp:268
ConsoleLogger(const ConsoleLogger &)=delete
Definition ILogger.hpp:69
LogStream stream(Level level, const std::string &caller="")
Create a LogStream for streaming log messages.
Definition ILogger.hpp:165
Level
Logging levels.
Definition ILogger.hpp:21
@ LOG_CRITICAL
Definition ILogger.hpp:21
@ LOG_INFO
Definition ILogger.hpp:21
@ LOG_ERROR
Definition ILogger.hpp:21
@ LOG_WARNING
Definition ILogger.hpp:21
@ LOG_DEBUG
Definition ILogger.hpp:21