LogIt++
Header-only, macro-first C++ logging library
Loading...
Searching...
No Matches
WindowsDebugLogger.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_WINDOWSDEBUGLOGGER_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_WINDOWSDEBUGLOGGER_HPP_INCLUDED
4
7
8#include "ILogger.hpp"
9#include <atomic>
10#include <string>
11#include <iostream>
12#include <memory>
13#include <mutex>
14
15#if defined(_WIN32)
16#include <windows.h>
17#endif
18
19namespace logit {
20
33 class WindowsDebugLogger : public ILogger {
34 public:
35
38 struct Config {
39#ifdef __EMSCRIPTEN__
41 explicit Config(bool async_value = false)
42#else
44 explicit Config(bool async_value = true)
45#endif
46 : async(async_value)
49 , queue_policy(QueuePolicy::Block) {}
50
51 bool async;
53 std::size_t queue_capacity;
55 };
56
59
62 explicit WindowsDebugLogger(const Config& config) : m_config(config) {
64 m_executor.reset(new detail::SingleThreadExecutor());
65 m_executor->set_max_queue_size(m_config.queue_capacity);
66 m_executor->set_queue_policy(m_config.queue_policy);
67 }
68 }
69
72 bool async,
73 bool use_dedicated_executor,
74 std::size_t queue_capacity,
75 QueuePolicy queue_policy)
77 async,
78 use_dedicated_executor,
79 queue_capacity,
80 queue_policy)) {}
81
88 void set_config(const Config& config) {
89 std::unique_ptr<detail::SingleThreadExecutor> old_executor;
90 {
91 std::unique_lock<std::mutex> lock(m_lifecycle_mutex);
92 if (m_shutdown.load(std::memory_order_acquire)) return;
93 if (m_config.async) {
94 if (m_executor) {
95 m_executor->wait();
96 } else {
98 }
99 }
100 m_config.async = config.async;
105 if (!m_executor) {
107 }
108 m_executor->set_max_queue_size(m_config.queue_capacity);
109 m_executor->set_queue_policy(m_config.queue_policy);
110 } else if (m_executor) {
111 old_executor = std::move(m_executor);
112 m_executor.reset();
113 }
114 }
115 if (old_executor) {
116 old_executor->shutdown();
117 }
118 }
119
128 bool set_queue_config(std::size_t queue_capacity,
129 QueuePolicy queue_policy) {
130 std::lock_guard<std::mutex> lifecycle_lock(m_lifecycle_mutex);
131
132 if (m_shutdown.load(std::memory_order_acquire)) {
133 return false;
134 }
135
136 m_config.queue_capacity = queue_capacity;
137 m_config.queue_policy = queue_policy;
138
139 if (!m_executor) {
140 return false;
141 }
142
143 m_executor->set_max_queue_size(queue_capacity);
144 m_executor->set_queue_policy(queue_policy);
145 return true;
146 }
147
155 void log(const LogRecord& record, const std::string& message) override {
156 std::lock_guard<std::mutex> lifecycle_lock(m_lifecycle_mutex);
157 if (m_shutdown.load(std::memory_order_acquire)) return;
158 if (m_config.async) {
159 if (m_executor) {
160 m_executor->add_task([message]() {
161 write_impl(message);
162 });
163 } else {
165 write_impl(message);
166 });
167 }
168 } else {
169 write_impl(message);
170 }
171 m_last_log_ts.store(record.timestamp_ms);
172 }
173
177 std::string get_string_param(const LoggerParam& param) const override {
178 switch (param) {
180 return std::to_string(m_last_log_ts.load());
181 default:
182 break;
183 }
184 return {};
185 }
186
190 int64_t get_int_param(const LoggerParam& param) const override {
191 switch (param) {
193 return m_last_log_ts.load();
194 default:
195 break;
196 }
197 return 0;
198 }
199
203 double get_float_param(const LoggerParam& param) const override {
204 switch (param) {
206 return static_cast<double>(m_last_log_ts.load()) / 1000.0;
207 default:
208 break;
209 }
210 return 0.0;
211 }
212
214 void set_log_level(LogLevel level) override {
215 m_log_level = static_cast<int>(level);
216 }
217
219 LogLevel get_log_level() const override {
220 return static_cast<LogLevel>(m_log_level.load());
221 }
222
224 void wait() override {
225 std::lock_guard<std::mutex> lifecycle_lock(m_lifecycle_mutex);
226 if (!m_config.async) return;
227 if (m_executor) {
228 m_executor->wait();
229 } else {
231 }
232 }
233
235 void shutdown() override {
236 {
237 std::lock_guard<std::mutex> lifecycle_lock(m_lifecycle_mutex);
238 if (m_shutdown.exchange(true, std::memory_order_acq_rel)) return;
239 }
240 if (m_executor) {
241 m_executor->shutdown();
242 } else if (m_config.async) {
244 }
245 }
246
247 private:
250 std::atomic<int> m_log_level{static_cast<int>(LogLevel::LOG_LVL_TRACE)};
251 std::atomic<int64_t> m_last_log_ts{0};
252 std::atomic<bool> m_shutdown{false};
253 std::unique_ptr<detail::SingleThreadExecutor> m_executor;
254
256 bool async,
257 bool use_dedicated_executor,
258 std::size_t queue_capacity,
259 QueuePolicy queue_policy) {
260 Config config(async);
261 config.use_dedicated_executor = use_dedicated_executor;
262 config.queue_capacity = queue_capacity;
263 config.queue_policy = queue_policy;
264 return config;
265 }
266
267 static void write_impl(const std::string& message) {
268#if defined(_WIN32)
269 // Convert UTF-8 message to wide string for OutputDebugStringW.
270 if (message.empty()) {
271 OutputDebugStringW(L"\n");
272 return;
273 }
274 const int len = static_cast<int>(message.size());
275 const int wlen = MultiByteToWideChar(CP_UTF8, 0, message.c_str(), len, nullptr, 0);
276 if (wlen > 0) {
277 std::wstring wmsg;
278 wmsg.resize(static_cast<size_t>(wlen));
279 MultiByteToWideChar(CP_UTF8, 0, message.c_str(), len, &wmsg[0], wlen);
280 wmsg += L'\n';
281 OutputDebugStringW(wmsg.c_str());
282 } else {
283 OutputDebugStringA((message + "\n").c_str());
284 }
285#else
286 std::cerr << message << '\n';
287#endif
288 }
289 };
290
291} // namespace logit
292
293#endif // LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_WINDOWSDEBUGLOGGER_HPP_INCLUDED
Defines the interface for loggers used in the logging system.
Optional buffered snapshot access returns empty results by default.
Definition ILogger.hpp:47
Outputs formatted log messages to the Windows debug console or stderr.
std::atomic< int64_t > m_last_log_ts
std::unique_ptr< detail::SingleThreadExecutor > m_executor
void shutdown() override
Stops logger-owned asynchronous resources after draining pending messages.
WindowsDebugLogger()
Default constructor that uses default configuration.
WindowsDebugLogger(bool async, bool use_dedicated_executor, std::size_t queue_capacity, QueuePolicy queue_policy)
Constructor with asynchronous and dedicated executor options.
static void write_impl(const std::string &message)
void set_log_level(LogLevel level) override
Sets the minimal log level for this logger.
int64_t get_int_param(const LoggerParam &param) const override
Retrieves an integer parameter from the logger.
static Config make_config(bool async, bool use_dedicated_executor, std::size_t queue_capacity, QueuePolicy queue_policy)
WindowsDebugLogger(const Config &config)
Constructor with custom configuration.
LogLevel get_log_level() const override
Gets the minimal log level for this logger.
double get_float_param(const LoggerParam &param) const override
Retrieves a floating-point parameter from the logger.
void set_config(const Config &config)
Updates executor-related configuration at runtime.
std::string get_string_param(const LoggerParam &param) const override
Retrieves a string parameter from the logger.
bool set_queue_config(std::size_t queue_capacity, QueuePolicy queue_policy)
Updates queue_capacity and queue_policy at runtime without draining tasks.
void wait() override
Waits for all asynchronous tasks to complete.
void log(const LogRecord &record, const std::string &message) override
Logs a message to the Windows debug output or stderr.
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.
QueuePolicy
Queue overflow handling policy used by TaskExecutor and SingleThreadExecutor.
The primary namespace for the LogIt++ library.
LogLevel
Logging levels.
Definition enums.hpp:15
@ LOG_LVL_TRACE
Trace level logging.
LoggerParam
Enumeration for different logger parameters that can be retrieved.
Definition enums.hpp:47
@ LastLogTimestamp
The timestamp of the last log.
Stores log metadata and content.
Definition LogRecord.hpp:17
const int64_t timestamp_ms
Timestamp in milliseconds.
Definition LogRecord.hpp:19
Configuration for the Windows debug logger.
bool use_dedicated_executor
Use a dedicated executor instead of the global TaskExecutor; native builds create one worker thread p...
Config(bool async_value=true)
Initializes configuration.
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).