2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_CONSOLELOGGER_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_CONSOLELOGGER_HPP_INCLUDED
10#include <condition_variable>
18#include <emscripten/emscripten.h>
19#if defined(LOGIT_EM_BROWSER_COLORS)
20EM_JS(
void, log_ansi_js, (
int lvl,
const char* cmsg,
const char* cdefcolor), {
21 const msg = UTF8ToString(cmsg);
22 const def = UTF8ToString(cdefcolor);
23 const isNode = (typeof process !==
'undefined' && process.versions && process.versions.node);
24 const fn = lvl >= 5 ? console.error : (lvl == 4 ? console.warn : console.log);
25 if (isNode) { fn(msg);
return; }
26 const map = {30:
"black",31:
"darkred",32:
"darkgreen",33:
"olive",34:
"darkblue",35:
"purple",36:
"teal",37:
"lightgray",
27 90:
"gray",91:
"red",92:
"green",93:
"yellow",94:
"blue",95:
"magenta",96:
"cyan",97:
"white"};
28 const re = /\x1b\[(\d+)m/g;
29 let last = 0, m, style =
'color:' + def;
32 while ((m = re.exec(msg)) !== null) {
33 if (m.index > last) { fmt.push(
'%c' + msg.slice(last, m.index)); styles.push(style); }
34 style =
'color:' + (map[m[1]] || def);
37 if (last < msg.length) { fmt.push(
'%c' + msg.slice(last)); styles.push(style); }
38 fn(fmt.join(
''), ...styles);
41EM_JS(
void, log_level, (
int lvl,
const char* msg), {
42 const s = UTF8ToString(msg);
43 const fn = lvl >= 5 ? console.error : (lvl == 4 ? console.warn : console.log);
91 std::vector<ConsoleStreamRoute>
routes;
141 bool use_dedicated_executor,
142 std::size_t queue_capacity = 0,
146 use_dedicated_executor,
152 std::ostream& stream,
154 bool use_dedicated_executor,
155 std::size_t queue_capacity = 0,
159 use_dedicated_executor,
171 std::shared_ptr<detail::SingleThreadExecutor> old_executor;
173 std::unique_lock<std::mutex> lock(
m_mutex);
174 if (
m_shutdown.load(std::memory_order_acquire))
return;
188 old_executor->shutdown();
196 std::lock_guard<std::mutex> lock(
m_mutex);
207 void log(
const LogRecord& record,
const std::string& message)
override {
208 if (
m_shutdown.load(std::memory_order_acquire))
return;
210 std::unique_lock<std::mutex> lock(
m_mutex);
211 if (
m_shutdown.load(std::memory_order_acquire))
return;
213 const int lvl =
static_cast<int>(record.
log_level);
214 std::shared_ptr<detail::SingleThreadExecutor> executor =
m_executor;
216# if defined(LOGIT_EM_BROWSER_COLORS)
219 log_level(lvl, message.c_str());
223 auto msg_copy = std::string(message);
229 executor->add_task([
this, lvl, msg_copy, def_color]() {
230 std::lock_guard<std::mutex> inner_lock(
m_mutex);
231# if defined(LOGIT_EM_BROWSER_COLORS)
232 log_ansi_js(lvl, msg_copy.c_str(), text_color_to_css(def_color));
234 log_level(lvl, msg_copy.c_str());
239 std::lock_guard<std::mutex> inner_lock(
m_mutex);
240# if defined(LOGIT_EM_BROWSER_COLORS)
241 log_ansi_js(lvl, msg_copy.c_str(), text_color_to_css(def_color));
243 log_level(lvl, msg_copy.c_str());
249 std::unique_lock<std::mutex> lock(
m_mutex);
250 if (
m_shutdown.load(std::memory_order_acquire))
return;
252 std::shared_ptr<detail::SingleThreadExecutor> executor =
m_executor;
262 executor->add_task([
this, stream, message](){
263 std::lock_guard<std::mutex> lock(
m_mutex);
268 std::lock_guard<std::mutex> lock(
m_mutex);
289 return std::string();
333 std::unique_lock<std::mutex> lock(
m_mutex);
335 std::shared_ptr<detail::SingleThreadExecutor> executor =
m_executor;
347 if (
m_shutdown.exchange(
true, std::memory_order_acq_rel))
return;
348 std::shared_ptr<detail::SingleThreadExecutor> executor;
351 std::unique_lock<std::mutex> lock(
m_mutex);
358 executor->shutdown();
382 if (route.min_level > route.max_level)
continue;
383 if (level < route.min_level || level > route.max_level)
continue;
384 switch (route.kind) {
390 if (route.custom_stream)
return route.custom_stream;
400 return &stream == &std::cout || &stream == &std::cerr;
406# ifdef __EMSCRIPTEN__
409# elif defined(_WIN32)
411 handle_ansi_colors_windows(message, stream);
413 stream << message << std::endl;
416 stream << message << std::endl;
421 const std::shared_ptr<detail::SingleThreadExecutor>& executor,
423 if (!executor)
return;
430 bool use_dedicated_executor,
431 std::size_t queue_capacity,
434 config.
async = async;
461 std::lock_guard<std::mutex> lock(
m_mutex);
470# ifdef __EMSCRIPTEN__
472 const char* text_color_to_css(
TextColor color)
const {
490 default:
return "inherit";
498 enum class WinColor {
520 void handle_ansi_colors_windows(
const std::string& message, std::ostream& stream)
const {
521 std::string::size_type start = 0;
522 std::string::size_type pos = 0;
524 HANDLE handle_stdout = (&stream == &std::cerr)
525 ? GetStdHandle(STD_ERROR_HANDLE)
526 : GetStdHandle(STD_OUTPUT_HANDLE);
528 while ((pos = message.find(
"\033[", start)) != std::string::npos) {
531 stream << message.substr(start, pos - start);
535 std::string::size_type end_pos = message.find(
'm', pos);
536 if (end_pos != std::string::npos) {
538 std::string ansi_code = message.substr(pos + 2, end_pos - pos - 2);
539 apply_color_from_ansi_code(ansi_code, handle_stdout);
549 if (start < message.size()) {
550 stream << message.substr(start);
552 if (!message.empty()) stream << std::endl;
555 SetConsoleTextAttribute(handle_stdout,
static_cast<WORD
>(text_color_to_win_color(
m_config.
default_color)));
561 void apply_color_from_ansi_code(
const std::string& ansi_code, HANDLE handle_stdout)
const {
563 const int code = std::stoi(ansi_code);
565 case 30: color_value =
static_cast<WORD
>(WinColor::Black);
break;
566 case 31: color_value =
static_cast<WORD
>(WinColor::DarkRed);
break;
567 case 32: color_value =
static_cast<WORD
>(WinColor::DarkGreen);
break;
568 case 33: color_value =
static_cast<WORD
>(WinColor::DarkYellow);
break;
569 case 34: color_value =
static_cast<WORD
>(WinColor::DarkBlue);
break;
570 case 35: color_value =
static_cast<WORD
>(WinColor::DarkMagenta);
break;
571 case 36: color_value =
static_cast<WORD
>(WinColor::DarkCyan);
break;
572 case 37: color_value =
static_cast<WORD
>(WinColor::Gray);
break;
573 case 90: color_value =
static_cast<WORD
>(WinColor::DarkGray);
break;
574 case 91: color_value =
static_cast<WORD
>(WinColor::Red);
break;
575 case 92: color_value =
static_cast<WORD
>(WinColor::Green);
break;
576 case 93: color_value =
static_cast<WORD
>(WinColor::Yellow);
break;
577 case 94: color_value =
static_cast<WORD
>(WinColor::Blue);
break;
578 case 95: color_value =
static_cast<WORD
>(WinColor::Magenta);
break;
579 case 96: color_value =
static_cast<WORD
>(WinColor::Cyan);
break;
580 case 97: color_value =
static_cast<WORD
>(WinColor::White);
break;
586 SetConsoleTextAttribute(handle_stdout, color_value);
592 WinColor text_color_to_win_color(
const TextColor& color)
const {
610 default:
return WinColor::White;
621# ifdef __EMSCRIPTEN__
624# elif defined(_WIN32)
625 handle_ansi_colors_windows(std::string(), *
m_stream);
Level-based output stream routing for ConsoleLogger.
Defines the interface for loggers used in the logging system.
PendingEnqueue(ConsoleLogger &logger)
PendingEnqueue(const PendingEnqueue &)=delete
PendingEnqueue & operator=(const PendingEnqueue &)=delete
Outputs log messages to the console with optional ANSI color support.
void log(const LogRecord &record, const std::string &message) override
Logs a message to the console with thread safety.
ConsoleLogger()
Default constructor that uses default configuration and std::cout.
double get_float_param(const LoggerParam ¶m) const override
Retrieves a floating-point parameter from the logger.
LogLevel get_log_level() const override
Gets the minimal log level for this logger.
std::atomic< bool > m_shutdown
std::mutex m_mutex
Mutex to protect console output.
int64_t get_last_log_ts() const
Retrieves the timestamp of the last log.
int64_t get_time_since_last_log() const
Retrieves the time since the last log.
static bool is_standard_console_stream(const std::ostream &stream)
Returns true for streams whose console handle we may drive (std::cout, std::cerr).
ConsoleLogger(std::ostream &stream, const Config &config)
Constructor with a custom primary output stream and configuration.
void wait_for_pending_enqueues(std::unique_lock< std::mutex > &lock)
Config get_config() const
Gets the current logger configuration.
std::string get_string_param(const LoggerParam ¶m) const override
Retrieves a string parameter from the logger.
ConsoleLogger(std::ostream &stream, bool async, bool use_dedicated_executor, std::size_t queue_capacity=0, QueuePolicy queue_policy=QueuePolicy::Block)
Constructor with a custom primary output stream, async mode, and executor options.
static Config make_config(bool async, bool use_dedicated_executor, std::size_t queue_capacity, QueuePolicy queue_policy)
void set_config(const Config &config)
Sets the logger configuration.
static void configure_executor(const std::shared_ptr< detail::SingleThreadExecutor > &executor, const Config &config)
std::shared_ptr< detail::SingleThreadExecutor > m_executor
void shutdown() override
Stops the dedicated executor after draining pending messages.
std::size_t m_pending_enqueues
int64_t get_int_param(const LoggerParam ¶m) const override
Retrieves an integer parameter from the logger.
ConsoleLogger(const bool async)
Constructor with asynchronous flag and std::cout.
std::atomic< int > m_log_level
void set_log_level(LogLevel level) override
Sets the minimal log level for this logger.
std::ostream * m_stream
Primary output stream; lifetime owned by the caller.
std::atomic< int64_t > m_last_log_ts
ConsoleLogger(const Config &config)
Constructor with custom configuration and the default std::cout stream.
ConsoleLogger(std::ostream &stream, const bool async)
Constructor with asynchronous flag and a custom primary output stream.
void write_colored_message(std::ostream &stream, const std::string &message) const
Writes one formatted message to a stream, applying colors when supported.
std::ostream * select_stream_for(LogLevel level) const
Selects the target stream for a given log level.
ConsoleLogger(bool async, bool use_dedicated_executor, std::size_t queue_capacity=0, QueuePolicy queue_policy=QueuePolicy::Block)
Constructor with asynchronous and dedicated executor options.
Config m_config
Configuration for the console logger.
void wait() override
Waits for all asynchronous tasks to complete.
std::condition_variable m_enqueue_cv
ConsoleLogger(std::ostream &stream)
Constructor with a custom primary output stream and default config.
void finish_pending_enqueue()
void reset_color()
Resets the console text color to the default.
Optional buffered snapshot access returns empty results by default.
Per-instance single-thread executor for isolated async logging.
void add_task(std::function< void()> task)
Enqueue a task for asynchronous execution.
void wait()
Block until the queue is empty or a shutdown is requested.
static TaskExecutor & get_instance()
Returns the global executor instance.
#define LOGIT_CURRENT_TIMESTAMP_MS()
Macro to get the current timestamp in milliseconds.
#define LOGIT_DEFAULT_COLOR
Defines the default color for console output.
QueuePolicy
Queue overflow handling policy used by TaskExecutor and SingleThreadExecutor.
The primary namespace for the LogIt++ library.
std::string to_string(LogLevel level, int mode=0)
Convert LogLevel to a std::string representation.
@ LOG_LVL_TRACE
Trace level logging.
LoggerParam
Enumeration for different logger parameters that can be retrieved.
@ TimeSinceLastLog
The time elapsed since the last log in seconds.
@ LastLogTimestamp
The timestamp of the last log.
TextColor
Text colors for console output.
@ Cout
Routes records to std::cout.
@ Custom
Routes records to a caller-provided std::ostream pointer.
@ Cerr
Routes records to std::cerr.
Configuration for the console logger.
bool async
Flag indicating whether logging should be asynchronous.
QueuePolicy queue_policy
Overflow policy for the dedicated executor.
std::size_t queue_capacity
Maximum queue size for the dedicated executor (0 = unlimited).
TextColor default_color
Default text color for console output.
bool use_dedicated_executor
Use a dedicated executor instead of the global TaskExecutor; native builds create one worker thread p...
std::vector< ConsoleStreamRoute > routes
Optional level-based stream routing.
Stores log metadata and content.
const LogLevel log_level
Log level (severity).
const int64_t timestamp_ms
Timestamp in milliseconds.