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 logFile_.flush(); // Force immediate write to disk
155 }
156 };
157
159 std::lock_guard<std::mutex> lock(logMutex_);
160 currentLevel_ = level;
161 };
162
163 [[nodiscard]]
165 return currentLevel_;
166 };
167
168 void setAppPrefix(const std::string &prefix) override {
169 std::lock_guard<std::mutex> lock(logMutex_);
170 appPrefix_ = prefix;
171 };
172
173 [[nodiscard]]
174 std::string getAppPrefix() const override {
175 return appPrefix_;
176 };
177
178 bool enableFileLogging(const std::string &filename) override {
179 std::lock_guard<std::mutex> lock(logMutex_);
180 try {
181 logFile_.open(filename, std::ios::out | std::ios::app);
182 return logFile_.is_open();
183 } catch (const std::ios_base::failure &e) {
184 std::cerr << "Failed to open log file: " << filename << " - " << e.what() << "\n";
185 return false;
186 } catch (const std::exception &e) {
187 std::cerr << "Failed to open log file: " << filename << " - " << e.what() << "\n";
188 return false;
189 } catch (...) {
190 std::cerr << "Failed to open log file: " << filename << "\n";
191 return false;
192 }
193 };
194
195 void disableFileLogging() override {
196 std::lock_guard<std::mutex> lock(logMutex_);
197 if (logFile_.is_open()) {
198 logFile_.close();
199 }
200 };
201
208 static std::string levelToString(dotnamecpp::logging::Level level) {
209 switch (level) {
210 case dotnamecpp::logging::Level::LOG_DEBUG: return "DBG";
211 case dotnamecpp::logging::Level::LOG_INFO: return "INF";
213 case dotnamecpp::logging::Level::LOG_ERROR: return "ERR";
215 default: return "INF";
216 }
217 }
218
223 static void resetConsoleColor() {
224#ifdef _WIN32
225 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
226 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
227#elif defined(__EMSCRIPTEN__)
228// no colors, no reset
229#else
230 std::cout << "\033[0m";
231#endif
232 }
233
234#ifdef _WIN32
235 static void setConsoleColorWindows(dotnamecpp::logging::Level level) {
236 const std::map<dotnamecpp::logging::Level, WORD> colorMap = {
238 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY},
239 {dotnamecpp::logging::Level::LOG_INFO, FOREGROUND_GREEN | FOREGROUND_INTENSITY},
241 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY},
242 {dotnamecpp::logging::Level::LOG_ERROR, FOREGROUND_RED | FOREGROUND_INTENSITY},
244 FOREGROUND_RED | FOREGROUND_INTENSITY | FOREGROUND_BLUE }};
245 auto it = colorMap.find(level);
246 if (it != colorMap.end()) {
247 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), it->second);
248 } else {
250 }
251 }
252#else
254 static const std::map<dotnamecpp::logging::Level, const char *> colorMap = {
260 auto it = colorMap.find(level);
261 if (it != colorMap.end()) {
262 std::cout << it->second;
263 } else {
265 }
266 }
267#endif
268
270#ifdef _WIN32
271 setConsoleColorWindows(level);
272#elif EMSCRIPTEN
273 // no colors
274#else
275 setConsoleColorUnix(level);
276#endif
277 }
278
279private:
280 std::string headerName_ = "DotNameLib";
281 bool includeName_ = true;
282 bool includeTime_ = true;
283 bool includeCaller_ = true;
284 bool includeLevel_ = true;
285
295 void logToStream(std::ostream &stream, dotnamecpp::logging::Level level,
296 const std::string &message, const std::string &caller, const std::tm &now_tm) {
297 setConsoleColor(level);
298 stream << buildHeader(now_tm, caller, level) << message;
300 if (addNewLine_) {
301 stream << "\n";
302 }
303 // Explicitly flush the stream to ensure immediate output
304 stream.flush();
305 }
306
315 std::string buildHeader(const std::tm &now_tm, const std::string &caller,
316 dotnamecpp::logging::Level level) const {
317 std::ostringstream header;
318 if (includeName_) {
319 header << "[" << headerName_ << "] ";
320 }
321 if (includeTime_) {
322 header << "[" << std::put_time(&now_tm, "%d-%m-%Y %H:%M:%S") << "] ";
323 }
324 if (includeCaller_ && !caller.empty()) {
325 header << "[" << caller << "] ";
326 }
327 if (includeLevel_) {
328 header << "[" << levelToString(level) << "] ";
329 }
330 return header.str();
331 }
332
333public:
339 void setHeaderName(const std::string &headerName) {
340 std::lock_guard<std::mutex> lock(logMutex_);
341 headerName_ = headerName;
342 }
343
349 void showHeaderName(bool includeName) {
350 std::lock_guard<std::mutex> lock(logMutex_);
351 includeName_ = includeName;
352 }
353
359 void showHeaderTime(bool includeTime) {
360 std::lock_guard<std::mutex> lock(logMutex_);
361 includeTime_ = includeTime;
362 }
363
369 void showHeaderCaller(bool includeCaller) {
370 std::lock_guard<std::mutex> lock(logMutex_);
371 includeCaller_ = includeCaller;
372 }
373
379 void showHeaderLevel(bool includeLevel) {
380 std::lock_guard<std::mutex> lock(logMutex_);
381 includeLevel_ = includeLevel;
382 }
383
389 void noHeader(bool noHeader) {
390 if (noHeader) {
391 showHeaderName(false);
392 showHeaderTime(false);
393 showHeaderCaller(false);
394 showHeaderLevel(false);
395 } else {
396 showHeaderName(true);
397 showHeaderTime(true);
398 showHeaderCaller(true);
399 showHeaderLevel(true);
400 }
401 }
402
411 void visibleHeaders(bool incName, bool incTime, bool incCaller, bool incLevel) {
412 showHeaderName(incName);
413 showHeaderTime(incTime);
414 showHeaderCaller(incCaller);
415 showHeaderLevel(incLevel);
416 }
417
423 void setColorEnabled(bool enabled) {
424 std::lock_guard<std::mutex> lock(logMutex_);
425 colorEnabled_ = enabled;
426 autoDetectColor_ = false; // Manual override disables auto-detection
427 }
428
434 void setAutoDetectColor(bool autoDetect) {
435 std::lock_guard<std::mutex> lock(logMutex_);
436 autoDetectColor_ = autoDetect;
437 }
438
439private:
445 bool shouldUseColors() const {
446 if (!autoDetectColor_) {
447 return colorEnabled_;
448 }
449 // Auto-detect: check if stdout is a TTY
450#ifdef __EMSCRIPTEN__
451 return false; // No color support in Emscripten
452#else
453 return colorEnabled_ && (isatty(fileno(stdout)) != 0);
454#endif
455 }
456}; // class ConsoleLogger
457
458#endif
void showHeaderTime(bool includeTime)
Show or hide the header time in the log output.
Definition ConsoleLogger.hpp:359
ConsoleLogger & operator=(ConsoleLogger &&other) noexcept
Definition ConsoleLogger.hpp:63
dotnamecpp::logging::Level getLevel() const override
Get the Level object.
Definition ConsoleLogger.hpp:164
~ConsoleLogger()
Definition ConsoleLogger.hpp:49
void setLevel(dotnamecpp::logging::Level level) override
Set the Level object.
Definition ConsoleLogger.hpp:158
void setAppPrefix(const std::string &prefix) override
Set the application prefix for log messages.
Definition ConsoleLogger.hpp:168
static std::string levelToString(dotnamecpp::logging::Level level)
Convert a logging level to its string representation.
Definition ConsoleLogger.hpp:208
void showHeaderName(bool includeName)
Show or hide the header name in the log output.
Definition ConsoleLogger.hpp:349
void noHeader(bool noHeader)
Show or hide all headers in the log output.
Definition ConsoleLogger.hpp:389
static void resetConsoleColor()
Reset the console color to default.
Definition ConsoleLogger.hpp:223
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:253
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:195
void showHeaderLevel(bool includeLevel)
Show or hide the header level in the log output.
Definition ConsoleLogger.hpp:379
std::string getAppPrefix() const override
Get the App Prefix object.
Definition ConsoleLogger.hpp:174
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:178
void showHeaderCaller(bool includeCaller)
Show or hide the header caller in the log output.
Definition ConsoleLogger.hpp:369
void setHeaderName(const std::string &headerName)
Set the Header Name object.
Definition ConsoleLogger.hpp:339
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:434
void visibleHeaders(bool incName, bool incTime, bool incCaller, bool incLevel)
Show or hide specific headers in the log output.
Definition ConsoleLogger.hpp:411
void setColorEnabled(bool enabled)
Enable or disable colored output.
Definition ConsoleLogger.hpp:423
static void setConsoleColor(dotnamecpp::logging::Level level)
Definition ConsoleLogger.hpp:269
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