Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
thread_logger.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11#pragma once
12
13#include <string>
14#include <string_view>
15#include <chrono>
16#include <sstream>
17#include <iomanip>
18#include <thread>
19#include <mutex>
20#include <iostream>
21#include <atomic>
22#include <cstdlib>
23#include <ctime>
24
25namespace kcenon::thread {
26
42enum class log_level {
43 trace,
44 debug,
45 info,
46 warning,
47 error,
49};
50
72public:
89 // Intentionally leak to avoid static destruction order issues
90 // Logger may be accessed during other singletons' destruction
91 static thread_logger* logger = []() {
92 auto* ptr = new thread_logger();
93 // Note: atexit handler is registered early by thread_logger_init.cpp
94 // We register here as well for safety (multiple calls to atexit with
95 // the same function are safe per C++ standard - they just add multiple
96 // entries, and prepare_shutdown() is idempotent)
97 std::atexit(prepare_shutdown);
98 return ptr;
99 }();
100 return *logger;
101 }
102
110 static void prepare_shutdown() {
111 is_shutting_down_.store(true, std::memory_order_release);
112 }
113
117 static bool is_shutting_down() {
118 return is_shutting_down_.load(std::memory_order_acquire);
119 }
120
128 [[deprecated(
129 "Use 'common::interfaces::ILogger' via thread_context instead. "
130 "Will be removed in v2.0.")]]
131 void set_enabled(bool enabled) {
132 enabled_ = enabled;
133 }
134
141 [[deprecated(
142 "Use 'thread_context::has_logger()' instead. "
143 "Will be removed in v2.0.")]]
144 bool is_enabled() const {
145 return enabled_;
146 }
147
155 [[deprecated(
156 "Configure log level on 'common::interfaces::ILogger' instead. "
157 "Will be removed in v2.0.")]]
158 void set_level(log_level level) {
159 min_level_ = level;
160 }
161
173 [[deprecated(
174 "Use 'thread_context::log()' with 'common::interfaces::ILogger' "
175 "instead. Will be removed in v2.0.")]]
176 void log(log_level level, std::string_view thread_name,
177 std::string_view message, std::string_view context = "") {
178 // Early return during shutdown to avoid accessing potentially destroyed resources
179 if (is_shutting_down_.load(std::memory_order_acquire)) {
180 return;
181 }
182
183 if (!enabled_ || level < min_level_) {
184 return;
185 }
186
187 std::lock_guard<std::mutex> lock(mutex_);
188
189 auto now = std::chrono::system_clock::now();
190 auto time_t_val = std::chrono::system_clock::to_time_t(now);
191 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
192 now.time_since_epoch()) % 1000;
193
194 // Use thread-safe localtime variant
195 std::tm tm_buf{};
196#if defined(_MSC_VER) || defined(_WIN32)
197 localtime_s(&tm_buf, &time_t_val);
198#else
199 localtime_r(&time_t_val, &tm_buf);
200#endif
201
202 std::cerr << "["
203 << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S")
204 << "." << std::setfill('0') << std::setw(3) << ms.count()
205 << "] "
206 << "[" << level_to_string(level) << "] "
207 << "[Thread:" << thread_name << "] "
208 << "[TID:" << std::this_thread::get_id() << "] "
209 << message;
210
211 if (!context.empty()) {
212 std::cerr << " | Context: " << context;
213 }
214
215 std::cerr << std::endl;
216 }
217
225 template<typename ErrorType>
226 [[deprecated(
227 "Use 'thread_context::log()' with 'common::interfaces::ILogger' "
228 "instead. Will be removed in v2.0.")]]
229 void log_error(std::string_view thread_name, const ErrorType& error) {
230 // Early return during shutdown
231 if (is_shutting_down_.load(std::memory_order_acquire) || !enabled_) {
232 return;
233 }
234
235 std::ostringstream oss;
236 oss << "Error code: " << error.code()
237 << ", Message: " << error.message();
238
239 log(log_level::error, thread_name, oss.str());
240 }
241
242private:
243 // Static shutdown flag - checked before any logging operation
244 // Uses inline to allow definition in header (C++17)
245 static inline std::atomic<bool> is_shutting_down_{false};
246
247 thread_logger() = default;
248 ~thread_logger() = default;
249 thread_logger(const thread_logger&) = delete;
251
252 static const char* level_to_string(log_level level) {
253 switch (level) {
254 case log_level::trace: return "TRACE";
255 case log_level::debug: return "DEBUG";
256 case log_level::info: return "INFO";
257 case log_level::warning: return "WARN";
258 case log_level::error: return "ERROR";
259 case log_level::critical: return "CRITICAL";
260 default: return "UNKNOWN";
261 }
262 }
263
264 // Default to warning level to minimize overhead in production
265 // Use set_level(log_level::info) or set_level(log_level::debug) for verbose logging
266 bool enabled_ = true;
268 std::mutex mutex_;
269
270 // Lightweight mode: disable structured logging entirely
271 // When enabled, logging becomes a no-op with minimal overhead
272 bool lightweight_mode_ = false;
273
274public:
288 [[deprecated(
289 "Use a null 'common::interfaces::ILogger' in thread_context to "
290 "disable logging. Will be removed in v2.0.")]]
291 void set_lightweight_mode(bool enabled) {
292 lightweight_mode_ = enabled;
293 // Disable logging when in lightweight mode
294 if (enabled) {
295 enabled_ = false;
296 }
297 }
298
305 [[deprecated(
306 "Superseded by 'common::interfaces::ILogger' injection. "
307 "Will be removed in v2.0.")]]
308 bool is_lightweight_mode() const {
309 return lightweight_mode_;
310 }
311};
312
313} // namespace kcenon::thread
Represents an error in the thread system.
error_code code() const noexcept
Gets the error code.
const std::string & message() const noexcept
Gets the error message.
Structured logger for thread system.
thread_logger & operator=(const thread_logger &)=delete
void log_error(std::string_view thread_name, const ErrorType &error)
Log error with error code.
static const char * level_to_string(log_level level)
static thread_logger & instance()
Get singleton instance.
void set_enabled(bool enabled)
Enable/disable logging.
bool is_enabled() const
Check if logging is enabled.
static void prepare_shutdown()
Prepare for process shutdown.
bool is_lightweight_mode() const
Check if in lightweight mode.
void log(log_level level, std::string_view thread_name, std::string_view message, std::string_view context="")
Log a message with context.
static std::atomic< bool > is_shutting_down_
static bool is_shutting_down()
Check if shutdown is in progress.
void set_level(log_level level)
Set minimum log level.
thread_logger(const thread_logger &)=delete
void set_lightweight_mode(bool enabled)
Enable lightweight mode (disables all logging for maximum performance).
@ critical
At or above max_size, queue is full.
Core threading foundation of the thread system library.
Definition thread_impl.h:17
log_level
Logging severity levels (legacy).
@ trace
Finest-grained informational events.
@ debug
Fine-grained informational events for debugging.
@ info
Informational messages highlighting progress.
@ error
Error events that might still allow continuation.