Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
logger_integration.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
19
21#include <atomic>
22#include <chrono>
23#include <cstdio>
24#include <iomanip>
25#include <iostream>
26#include <mutex>
27#include <sstream>
28
30
31// Helper function to convert log level to string
32static const char* level_to_string(log_level level) {
33 switch (level) {
34 case log_level::trace: return "TRACE";
35 case log_level::debug: return "DEBUG";
36 case log_level::info: return "INFO ";
37 case log_level::warn: return "WARN ";
38 case log_level::error: return "ERROR";
39 case log_level::fatal: return "FATAL";
40 default: return "UNKN ";
41 }
42}
43
44// Helper function to get current timestamp (thread-safe)
45static std::string get_timestamp() {
46 auto now = std::chrono::system_clock::now();
47 auto time_t_val = std::chrono::system_clock::to_time_t(now);
48 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
49 now.time_since_epoch()) % 1000;
50
51 std::tm tm_buf{};
52#ifdef _WIN32
53 localtime_s(&tm_buf, &time_t_val); // Windows thread-safe version
54#else
55 localtime_r(&time_t_val, &tm_buf); // POSIX thread-safe version
56#endif
57
58 std::stringstream ss;
59 ss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
60 ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
61 return ss.str();
62}
63
64//============================================================================
65// common_system_logger_adapter implementation (only when common_system available)
66//============================================================================
67
68#if KCENON_WITH_COMMON_SYSTEM
69
70common_system_logger_adapter::common_system_logger_adapter(const std::string& logger_name)
71 : logger_name_(logger_name) {}
72
73std::shared_ptr<kcenon::common::interfaces::ILogger>
74common_system_logger_adapter::get_logger() const {
75 if (logger_name_.empty()) {
76 return kcenon::common::interfaces::get_logger();
77 }
78 return kcenon::common::interfaces::get_logger(logger_name_);
79}
80
81void common_system_logger_adapter::log(log_level level, const std::string& message) {
82 auto logger = get_logger();
83 if (logger) {
84 logger->log(to_common_level(level), message);
85 }
86}
87
88void common_system_logger_adapter::log(log_level level, const std::string& message,
89 const std::string& file, int line,
90 const std::string& function) {
91 auto logger = get_logger();
92 if (logger) {
93 // Use log_entry API for common_system v3.0.0 compatibility
94 // See: https://github.com/kcenon/network_system/issues/338
95 kcenon::common::interfaces::log_entry entry;
96 entry.level = to_common_level(level);
97 entry.message = message;
98 entry.file = file;
99 entry.line = line;
100 entry.function = function;
101 entry.timestamp = std::chrono::system_clock::now();
102 logger->log(entry);
103 }
104}
105
106bool common_system_logger_adapter::is_level_enabled(log_level level) const {
107 auto logger = get_logger();
108 return logger ? logger->is_enabled(to_common_level(level)) : false;
109}
110
111void common_system_logger_adapter::flush() {
112 auto logger = get_logger();
113 if (logger) {
114 logger->flush();
115 }
116}
117
118#endif // KCENON_WITH_COMMON_SYSTEM
119
120//============================================================================
121// basic_logger implementation
122//============================================================================
123
125public:
126 explicit impl(log_level min_level) : min_level_(static_cast<int>(min_level)) {}
127
128 void log(log_level level, const std::string& message) {
129 if (static_cast<int>(level) < min_level_) return;
130
131 std::lock_guard<std::mutex> lock(mutex_);
132
133 auto timestamp = get_timestamp();
134 std::ostringstream oss;
135 oss << "[" << timestamp << "] "
136 << "[" << level_to_string(level) << "] "
137 << "[network_system] "
138 << message;
139
140 auto* target = (level >= log_level::error) ? stderr : stdout;
141 const auto& record = oss.str();
142 std::fwrite(record.data(), 1, record.size(), target);
143 std::fputc('\n', target);
144 std::fflush(target);
145 }
146
147 void log(log_level level, const std::string& message,
148 const std::string& file, int line, const std::string& function) {
149 if (static_cast<int>(level) < min_level_) return;
150
151 std::lock_guard<std::mutex> lock(mutex_);
152
153 auto timestamp = get_timestamp();
154 std::ostringstream oss;
155 oss << "[" << timestamp << "] "
156 << "[" << level_to_string(level) << "] "
157 << "[network_system] "
158 << message
159 << " (" << file << ":" << line << " in " << function << ")";
160
161 auto* target = (level >= log_level::error) ? stderr : stdout;
162 const auto& record = oss.str();
163 std::fwrite(record.data(), 1, record.size(), target);
164 std::fputc('\n', target);
165 std::fflush(target);
166 }
167
168 bool is_level_enabled(log_level level) const {
169 return static_cast<int>(level) >= min_level_;
170 }
171
172 void flush() {
173 std::lock_guard<std::mutex> lock(mutex_);
174 std::fflush(stdout);
175 std::fflush(stderr);
176 }
177
179 min_level_ = static_cast<int>(level);
180 }
181
183 return static_cast<log_level>(min_level_.load());
184 }
185
186private:
187 mutable std::mutex mutex_;
188 std::atomic<int> min_level_;
189};
190
191basic_logger::basic_logger(log_level min_level)
192 : pimpl_(std::make_unique<impl>(min_level)) {}
193
195
196void basic_logger::log(log_level level, const std::string& message) {
197 pimpl_->log(level, message);
198}
199
200void basic_logger::log(log_level level, const std::string& message,
201 const std::string& file, int line, const std::string& function) {
202 pimpl_->log(level, message, file, line, function);
203}
204
206 return pimpl_->is_level_enabled(level);
207}
208
210 pimpl_->flush();
211}
212
216
220
221//============================================================================
222// logger_integration_manager implementation
223//
224// When KCENON_WITH_COMMON_SYSTEM is defined, uses common_system_logger_adapter.
225// Otherwise, uses basic_logger for standalone operation.
226//============================================================================
227
229public:
231#if KCENON_WITH_COMMON_SYSTEM
232 // Use common_system_logger_adapter by default
233 // It delegates to GlobalLoggerRegistry which provides NullLogger fallback
234 logger_ = std::make_shared<common_system_logger_adapter>();
235#else
236 // Use basic_logger for standalone operation
237 logger_ = std::make_shared<basic_logger>();
238#endif
239 }
240
241 void set_logger(std::shared_ptr<logger_interface> logger) {
242 std::lock_guard<std::mutex> lock(mutex_);
243 logger_ = logger;
244 }
245
246 std::shared_ptr<logger_interface> get_logger() {
247 std::lock_guard<std::mutex> lock(mutex_);
248 if (!logger_) {
249#if KCENON_WITH_COMMON_SYSTEM
250 logger_ = std::make_shared<common_system_logger_adapter>();
251#else
252 logger_ = std::make_shared<basic_logger>();
253#endif
254 }
255 return logger_;
256 }
257
258 void log(log_level level, const std::string& message) {
259#if KCENON_WITH_COMMON_SYSTEM
260 // Delegate directly to common_system's GlobalLoggerRegistry
261 auto common_logger = kcenon::common::interfaces::get_logger();
262 if (common_logger) {
263 common_logger->log(to_common_level(level), message);
264 }
265#else
266 auto logger = get_logger();
267 if (logger) {
268 logger->log(level, message);
269 }
270#endif
271 }
272
273 void log(log_level level, const std::string& message,
274 const std::string& file, int line, const std::string& function) {
275#if KCENON_WITH_COMMON_SYSTEM
276 // Delegate directly to common_system's GlobalLoggerRegistry
277 // Use log_entry API for common_system v3.0.0 compatibility
278 auto common_logger = kcenon::common::interfaces::get_logger();
279 if (common_logger) {
280 kcenon::common::interfaces::log_entry entry;
281 entry.level = to_common_level(level);
282 entry.message = message;
283 entry.file = file;
284 entry.line = line;
285 entry.function = function;
286 entry.timestamp = std::chrono::system_clock::now();
287 common_logger->log(entry);
288 }
289#else
290 auto logger = get_logger();
291 if (logger) {
292 logger->log(level, message, file, line, function);
293 }
294#endif
295 }
296
297private:
298 mutable std::mutex mutex_;
299 std::shared_ptr<logger_interface> logger_;
300};
301
303 // Intentionally leak the singleton to avoid destruction order issues
304 // during sanitizer runs and shutdown hooks.
306 return *instance;
307}
308
311
313
314void logger_integration_manager::set_logger(std::shared_ptr<logger_interface> logger) {
315 pimpl_->set_logger(logger);
316}
317
318std::shared_ptr<logger_interface> logger_integration_manager::get_logger() {
319 return pimpl_->get_logger();
320}
321
322void logger_integration_manager::log(log_level level, const std::string& message) {
323 pimpl_->log(level, message);
324}
325
326void logger_integration_manager::log(log_level level, const std::string& message,
327 const std::string& file, int line, const std::string& function) {
328 pimpl_->log(level, message, file, line, function);
329}
330
331} // namespace kcenon::network::integration
void log(log_level level, const std::string &message, const std::string &file, int line, const std::string &function)
void log(log_level level, const std::string &message)
void log(log_level level, const std::string &message) override
Log a message with specified level.
bool is_level_enabled(log_level level) const override
Check if a log level is enabled.
void set_min_level(log_level level)
Set minimum log level.
void flush() override
Flush any buffered log messages.
log_level get_min_level() const
Get current minimum log level.
void set_logger(std::shared_ptr< logger_interface > logger)
void log(log_level level, const std::string &message, const std::string &file, int line, const std::string &function)
void log(log_level level, const std::string &message)
static logger_integration_manager & instance()
Get the singleton instance.
void log(log_level level, const std::string &message)
Log a message.
void set_logger(std::shared_ptr< logger_interface > logger)
Set the logger implementation.
std::shared_ptr< logger_interface > get_logger()
Get the current logger.
Feature flags for network_system.
Logger system integration interface for network_system.
static const char * level_to_string(log_level level)