Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
logger.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11
12#ifdef LOGGER_WITH_ANALYSIS
14#endif // LOGGER_WITH_ANALYSIS
15
16// Note: thread_system_backend was removed in Issue #225
17// thread_system is now optional and standalone_backend is the default
18
22#include <kcenon/common/patterns/result.h>
23
24#include <algorithm>
25#include <atomic>
26#include <chrono>
27#include <iostream>
28#include <shared_mutex>
29#include <type_traits>
30#include <unordered_map>
31#include <vector>
32
33namespace kcenon::logger {
34
35// Type alias for log_level
36using log_level = common::interfaces::log_level;
37
38namespace {
53bool meets_threshold(log_level level, log_level minimum) {
54 return static_cast<int>(level) >= static_cast<int>(minimum);
55}
56} // namespace
57
58// Simple implementation class for logger PIMPL
59class logger::impl {
60public:
62 std::size_t buffer_size_;
65 std::atomic<log_level> min_level_;
66 std::vector<std::shared_ptr<log_writer_interface>> writers_;
67 std::unordered_map<std::string, std::shared_ptr<log_writer_interface>> named_writers_; // Named writer storage
68 std::shared_mutex writers_mutex_; // Protects writers_ and named_writers_ from concurrent modification
69 std::unique_ptr<backends::integration_backend> backend_; // Integration backend
70 std::unique_ptr<log_collector> collector_; // Async log collector for async mode
71 std::unique_ptr<log_filter_interface> filter_; // Global filter for log entries
72 mutable std::shared_mutex filter_mutex_; // Protects filter_ from concurrent access
73 std::unique_ptr<log_router> router_; // Log router for message routing
74 mutable std::shared_mutex router_mutex_; // Protects router_ from concurrent access
75
76#ifdef LOGGER_WITH_ANALYSIS
77 // Real-time analysis
78 std::unique_ptr<analysis::realtime_log_analyzer> realtime_analyzer_; // Real-time log analyzer
79 mutable std::shared_mutex analyzer_mutex_; // Protects realtime_analyzer_
80#endif // LOGGER_WITH_ANALYSIS
81
82 // Unified context for structured logging (consolidates all context types)
83 unified_log_context context_; // Unified context (thread-safe internally)
84
85 // Log sampling
86 std::unique_ptr<sampling::log_sampler> sampler_; // Log sampler for volume reduction
87 mutable std::shared_mutex sampler_mutex_; // Protects sampler_
88
89 // Emergency flush support (for signal handlers)
90 static constexpr size_t emergency_buffer_size_ = 8192;
91 mutable char emergency_buffer_[emergency_buffer_size_]; // Static buffer for emergency use
92 std::atomic<size_t> emergency_buffer_used_{0}; // Track how much is used
93 std::atomic<int> emergency_fd_{-1}; // File descriptor for emergency writes
94
95 impl(bool async, std::size_t buffer_size, std::unique_ptr<backends::integration_backend> backend)
96 : async_mode_(async), buffer_size_(buffer_size), running_(false), metrics_enabled_(false),
97 min_level_(log_level::info), backend_(std::move(backend)),
98 router_(std::make_unique<log_router>()) {
99 // Reserve space to avoid reallocation during typical usage
100 writers_.reserve(10);
101
102 // Auto-detect backend if not provided
103 // Users can provide thread_system_backend or other backends via constructor
104 if (!backend_) {
105 backend_ = std::make_unique<backends::standalone_backend>();
106 }
107
108 // Initialize backend if required
109 if (backend_->requires_initialization()) {
110 backend_->initialize();
111 }
112
113 // Create log collector for async mode
114 if (async_mode_) {
115 collector_ = std::make_unique<log_collector>(buffer_size_);
116 }
117 }
118
120 if (backend_) {
121 backend_->shutdown();
122 }
123 }
124
134 void dispatch_to_writers(log_level level,
135 const std::string& message,
136 const std::string& file,
137 int line,
138 const std::string& function,
139 const log_entry& entry) {
140#ifdef LOGGER_WITH_ANALYSIS
141 // Real-time analysis if analyzer is set
142 {
143 std::shared_lock<std::shared_mutex> lock(analyzer_mutex_);
144 if (realtime_analyzer_) {
145 analysis::analyzed_log_entry analyzed_entry;
146 analyzed_entry.level = level;
147 analyzed_entry.message = message;
148 analyzed_entry.timestamp = entry.timestamp;
149 analyzed_entry.source_file = file;
150 analyzed_entry.source_line = line;
151 analyzed_entry.function_name = function;
152 realtime_analyzer_->analyze(analyzed_entry);
153 }
154 }
155#endif // LOGGER_WITH_ANALYSIS
156
157 // Check routing rules
158 std::vector<std::string> routed_writer_names;
159 bool is_exclusive = false;
160 {
161 std::shared_lock<std::shared_mutex> lock(router_mutex_);
162 if (router_) {
163 routed_writer_names = router_->get_writers_for_log(entry);
164 is_exclusive = router_->is_exclusive_routing();
165 }
166 }
167
168 auto now = std::chrono::system_clock::now();
169
170 if (is_exclusive) {
171 // Exclusive mode: only send to matched routes
172 // If no routes match, message is dropped (exclusive mode behavior)
173 if (!routed_writer_names.empty()) {
174 std::unordered_map<std::string, std::shared_ptr<log_writer_interface>> local_named_writers;
175 {
176 std::shared_lock<std::shared_mutex> lock(writers_mutex_);
177 local_named_writers = named_writers_;
178 }
179
180 // Create log_entry for routing
181 log_entry entry(level, message, file, line, function, now);
182
183 for (const auto& writer_name : routed_writer_names) {
184 auto it = local_named_writers.find(writer_name);
185 if (it != local_named_writers.end() && it->second) {
186 it->second->write(entry);
187 }
188 }
189 }
190 // No matched routes in exclusive mode = drop message
191 } else {
192 // Non-exclusive mode: send to all writers
193 std::vector<std::shared_ptr<log_writer_interface>> local_writers;
194 {
195 std::shared_lock<std::shared_mutex> lock(writers_mutex_);
196 local_writers = writers_;
197 }
198
199 // Create log_entry once for all writers
200 log_entry entry(level, message, file, line, function, now);
201
202 for (auto& writer : local_writers) {
203 if (writer) {
204 writer->write(entry);
205 }
206 }
207 }
208 }
209};
210
211logger::logger(bool async, std::size_t buffer_size, std::unique_ptr<backends::integration_backend> backend)
212 : pimpl_(std::make_unique<impl>(async, buffer_size, std::move(backend))) {
213 // Initialize logger with configuration
214}
215
216logger::~logger() {
217 if (pimpl_ && pimpl_->running_) {
218 stop();
219 }
220}
221
222common::VoidResult logger::start() {
223 if (pimpl_ && !pimpl_->running_) {
224 pimpl_->running_ = true;
225
226 // Start async collector if in async mode
227 if (pimpl_->async_mode_ && pimpl_->collector_) {
228 // Register all existing writers with the collector
229 {
230 std::shared_lock<std::shared_mutex> lock(pimpl_->writers_mutex_);
231 for (const auto& writer : pimpl_->writers_) {
232 if (writer) {
233 pimpl_->collector_->add_writer(writer);
234 }
235 }
236 }
237
238 // Start the background processing thread
239 pimpl_->collector_->start();
240 }
241 }
242 return common::ok();
243}
244
245common::VoidResult logger::stop() {
246 if (pimpl_ && pimpl_->running_) {
247 // Stop async collector if in async mode
248 // The collector's stop() drains the queue and flushes writers automatically
249 if (pimpl_->async_mode_ && pimpl_->collector_) {
250 pimpl_->collector_->stop();
251 } else {
252 // Synchronous mode: manually flush writers
253 flush();
254 }
255
256 pimpl_->running_ = false;
257 }
258 return common::ok();
259}
260
261bool logger::is_running() const {
262 return pimpl_ && pimpl_->running_;
263}
264
265common::VoidResult logger::add_writer(log_writer_ptr writer) {
266 if (pimpl_ && writer) {
267 std::shared_ptr<log_writer_interface> shared_writer(std::move(writer));
268
269 {
270 std::lock_guard<std::shared_mutex> lock(pimpl_->writers_mutex_);
271 pimpl_->writers_.push_back(shared_writer);
272 }
273
274 // Register with collector if in async mode and running
275 if (pimpl_->async_mode_ && pimpl_->collector_ && pimpl_->running_) {
276 pimpl_->collector_->add_writer(shared_writer);
277 }
278 }
279 return common::ok();
280}
281
282common::VoidResult logger::add_writer(const std::string& name, log_writer_ptr writer) {
283 if (!pimpl_) {
284 return common::make_error<std::monostate>(
286 "Logger not initialized",
287 "logger_system");
288 }
289 if (!writer) {
290 return common::make_error<std::monostate>(
291 static_cast<int>(logger_error_code::invalid_argument),
292 "Writer cannot be null",
293 "logger_system");
294 }
295
296 std::shared_ptr<log_writer_interface> shared_writer(std::move(writer));
297
298 {
299 std::lock_guard<std::shared_mutex> lock(pimpl_->writers_mutex_);
300 pimpl_->writers_.push_back(shared_writer);
301 if (!name.empty()) {
302 pimpl_->named_writers_[name] = shared_writer;
303 }
304 }
305
306 // Register with collector if in async mode and running
307 if (pimpl_->async_mode_ && pimpl_->collector_ && pimpl_->running_) {
308 pimpl_->collector_->add_writer(shared_writer);
309 }
310
311 return common::ok();
312}
313
314common::VoidResult logger::clear_writers() {
315 if (pimpl_) {
316 {
317 std::lock_guard<std::shared_mutex> lock(pimpl_->writers_mutex_);
318 pimpl_->writers_.clear();
319 pimpl_->named_writers_.clear();
320 }
321
322 // Clear collectors writers if in async mode
323 if (pimpl_->async_mode_ && pimpl_->collector_) {
324 pimpl_->collector_->clear_writers();
325 }
326 }
327 return common::ok();
328}
329
330bool logger::remove_writer(const std::string& name) {
331 if (!pimpl_ || name.empty()) {
332 return false;
333 }
334
335 std::lock_guard<std::shared_mutex> lock(pimpl_->writers_mutex_);
336
337 auto it = pimpl_->named_writers_.find(name);
338 if (it == pimpl_->named_writers_.end()) {
339 return false;
340 }
341
342 auto writer_to_remove = it->second;
343
344 // Remove from named_writers_ map
345 pimpl_->named_writers_.erase(it);
346
347 // Remove from writers_ vector
348 auto vec_it = std::find(pimpl_->writers_.begin(), pimpl_->writers_.end(), writer_to_remove);
349 if (vec_it != pimpl_->writers_.end()) {
350 pimpl_->writers_.erase(vec_it);
351 }
352
353 // Note: Cannot remove from collector's writers list as it doesn't support removal
354 // The writer will be skipped during iteration if it's no longer valid
355
356 return true;
357}
358
359log_writer_interface* logger::get_writer(const std::string& name) {
360 if (!pimpl_ || name.empty()) {
361 return nullptr;
362 }
363
364 std::shared_lock<std::shared_mutex> lock(pimpl_->writers_mutex_);
365
366 auto it = pimpl_->named_writers_.find(name);
367 if (it != pimpl_->named_writers_.end() && it->second) {
368 return it->second.get();
369 }
370
371 return nullptr;
372}
373
374// =========================================================================
375// ILogger interface implementation (common::interfaces::ILogger)
376// =========================================================================
377
378common::VoidResult logger::log(common::interfaces::log_level level,
379 const std::string& message) {
380 if (!pimpl_ || !meets_threshold(level, pimpl_->min_level_.load())) {
381 return common::ok();
382 }
383
384 // Create log entry for filtering and routing
385 log_entry entry(level, message);
386
387 // Apply filter if set
388 {
389 std::shared_lock<std::shared_mutex> filter_lock(pimpl_->filter_mutex_);
390 if (pimpl_->filter_) {
391 if (!pimpl_->filter_->should_log(entry)) {
392 return common::ok(); // Message filtered out (not an error)
393 }
394 }
395 }
396
397 // Apply sampling if set
398 {
399 std::shared_lock<std::shared_mutex> sampler_lock(pimpl_->sampler_mutex_);
400 if (pimpl_->sampler_ && pimpl_->sampler_->is_enabled()) {
401 if (!pimpl_->sampler_->should_sample(entry)) {
402 return common::ok(); // Message sampled out (not an error)
403 }
404 }
405 }
406
407 // Record metrics if enabled
408 auto start_time = std::chrono::high_resolution_clock::now();
409
410 // Synchronous path: dispatch with routing support
411 pimpl_->dispatch_to_writers(level, message, "", 0, "", entry);
412
413 // Update metrics after logging
414 if (pimpl_->metrics_enabled_) {
415 auto end_time = std::chrono::high_resolution_clock::now();
416 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
417 metrics::record_message_logged(duration.count());
418 }
419
420 return common::ok();
421}
422
423common::VoidResult logger::log(common::interfaces::log_level level,
424 std::string_view message,
425 const common::source_location& loc) {
426 if (!pimpl_ || !meets_threshold(level, pimpl_->min_level_.load())) {
427 return common::ok();
428 }
429
430 std::string msg_str(message);
431 std::string file_str(loc.file_name());
432 int line = loc.line();
433 std::string func_str(loc.function_name());
434
435 // Create log entry for filtering and routing
436 log_entry entry(level, msg_str, file_str, line, func_str);
437
438 // Apply filter if set
439 {
440 std::shared_lock<std::shared_mutex> filter_lock(pimpl_->filter_mutex_);
441 if (pimpl_->filter_) {
442 if (!pimpl_->filter_->should_log(entry)) {
443 return common::ok(); // Message filtered out
444 }
445 }
446 }
447
448 // Apply sampling if set
449 {
450 std::shared_lock<std::shared_mutex> sampler_lock(pimpl_->sampler_mutex_);
451 if (pimpl_->sampler_ && pimpl_->sampler_->is_enabled()) {
452 if (!pimpl_->sampler_->should_sample(entry)) {
453 return common::ok(); // Message sampled out
454 }
455 }
456 }
457
458 // Record metrics if enabled
459 auto start_time = std::chrono::high_resolution_clock::now();
460
461 // Use async path if in async mode
462 if (pimpl_->async_mode_ && pimpl_->collector_) {
463 // Enqueue to collector for background processing
464 auto now = std::chrono::system_clock::now();
465 pimpl_->collector_->enqueue(level, msg_str, file_str, line, func_str, now);
466
467 // Update metrics if enabled (async path is much faster)
468 if (pimpl_->metrics_enabled_) {
469 auto end_time = std::chrono::high_resolution_clock::now();
470 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
471 metrics::record_message_logged(duration.count());
472 }
473 return common::ok();
474 }
475
476 // Synchronous path: dispatch with routing support
477 pimpl_->dispatch_to_writers(level, msg_str, file_str, line, func_str, entry);
478
479 // Update metrics after logging
480 if (pimpl_->metrics_enabled_) {
481 auto end_time = std::chrono::high_resolution_clock::now();
482 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
483 metrics::record_message_logged(duration.count());
484 }
485
486 return common::ok();
487}
488
489common::VoidResult logger::log(const common::interfaces::log_entry& entry) {
490 if (!pimpl_ || !meets_threshold(entry.level, pimpl_->min_level_.load())) {
491 return common::ok();
492 }
493
494 std::string msg_str(entry.message);
495 std::string file_str(entry.file);
496 int line = entry.line;
497 std::string func_str(entry.function);
498
499 // Create log entry for filtering and routing
500 log_entry internal_entry(entry.level, msg_str, file_str, line, func_str);
501
502 // Apply filter if set
503 {
504 std::shared_lock<std::shared_mutex> filter_lock(pimpl_->filter_mutex_);
505 if (pimpl_->filter_) {
506 if (!pimpl_->filter_->should_log(internal_entry)) {
507 return common::ok();
508 }
509 }
510 }
511
512 // Apply sampling if set
513 {
514 std::shared_lock<std::shared_mutex> sampler_lock(pimpl_->sampler_mutex_);
515 if (pimpl_->sampler_ && pimpl_->sampler_->is_enabled()) {
516 if (!pimpl_->sampler_->should_sample(internal_entry)) {
517 return common::ok();
518 }
519 }
520 }
521
522 // Record metrics if enabled
523 auto start_time = std::chrono::high_resolution_clock::now();
524
525 // Use async path if in async mode
526 if (pimpl_->async_mode_ && pimpl_->collector_) {
527 auto now = std::chrono::system_clock::now();
528 pimpl_->collector_->enqueue(entry.level, msg_str, file_str, line, func_str, now);
529
530 if (pimpl_->metrics_enabled_) {
531 auto end_time = std::chrono::high_resolution_clock::now();
532 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
533 metrics::record_message_logged(duration.count());
534 }
535 return common::ok();
536 }
537
538 // Synchronous path: dispatch with routing support
539 pimpl_->dispatch_to_writers(entry.level, msg_str, file_str, line, func_str, internal_entry);
540
541 // Update metrics after logging
542 if (pimpl_->metrics_enabled_) {
543 auto end_time = std::chrono::high_resolution_clock::now();
544 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
545 metrics::record_message_logged(duration.count());
546 }
547
548 return common::ok();
549}
550
551bool logger::is_enabled(common::interfaces::log_level level) const {
552 return pimpl_ && meets_threshold(level, pimpl_->min_level_.load());
553}
554
555common::VoidResult logger::set_level(common::interfaces::log_level level) {
556 if (!pimpl_) {
557 return common::make_error<std::monostate>(
559 "Logger not initialized",
560 "logger_system");
561 }
562
563 pimpl_->min_level_.store(level);
564 return common::ok();
565}
566
567common::interfaces::log_level logger::get_level() const {
568 if (pimpl_) {
569 return pimpl_->min_level_.load();
570 }
571 return common::interfaces::log_level::info;
572}
573
574common::VoidResult logger::flush() {
575 if (!pimpl_) {
576 return common::make_error<std::monostate>(
578 "Logger not initialized",
579 "logger_system");
580 }
581
582 if (pimpl_->async_mode_ && pimpl_->collector_) {
583 // Async mode: collector handles both queue draining and writer flushing
584 pimpl_->collector_->flush();
585 } else {
586 // Synchronous mode: manually flush writers
587 std::vector<std::shared_ptr<log_writer_interface>> local_writers;
588 {
589 std::shared_lock<std::shared_mutex> lock(pimpl_->writers_mutex_);
590 local_writers = pimpl_->writers_;
591 }
592
593 for (auto& writer : local_writers) {
594 if (writer) {
595 writer->flush();
596 }
597 }
598 }
599
600 return common::ok();
601}
602
603common::VoidResult logger::enable_metrics_collection(bool enable) {
604 if (!pimpl_) {
605 return make_logger_void_result(logger_error_code::invalid_argument, "Logger not initialized");
606 }
607
608 pimpl_->metrics_enabled_ = enable;
609 if (!enable) {
611 }
612
613 return common::ok();
614}
615
616bool logger::is_metrics_collection_enabled() const {
617 return pimpl_ && pimpl_->metrics_enabled_;
618}
619
620result<logger_metrics> logger::get_current_metrics() const {
621 if (!pimpl_) {
624 "Logger not initialized"};
625 }
626
627 if (!pimpl_->metrics_enabled_) {
630 "Metrics collection is not enabled"};
631 }
632
633 // Return a copy of the current global metrics (thread-safe because of copy constructor)
634 // Use static factory method to avoid constructor ambiguity
636}
637
638// Emergency flush support implementation (critical_logger_interface)
639
640int logger::get_emergency_fd() const {
641 if (!pimpl_) {
642 return -1;
643 }
644 return pimpl_->emergency_fd_.load(std::memory_order_acquire);
645}
646
647const char* logger::get_emergency_buffer() const {
648 if (!pimpl_) {
649 return nullptr;
650 }
651 return pimpl_->emergency_buffer_;
652}
653
654size_t logger::get_emergency_buffer_size() const {
655 if (!pimpl_) {
656 return 0;
657 }
658 return pimpl_->emergency_buffer_used_.load(std::memory_order_acquire);
659}
660
661// Filter support implementation
662
663void logger::set_filter(std::unique_ptr<log_filter_interface> filter) {
664 if (pimpl_) {
665 std::lock_guard<std::shared_mutex> lock(pimpl_->filter_mutex_);
666 pimpl_->filter_ = std::move(filter);
667 }
668}
669
670bool logger::has_filter() const {
671 if (!pimpl_) {
672 return false;
673 }
674 std::shared_lock<std::shared_mutex> lock(pimpl_->filter_mutex_);
675 return pimpl_->filter_ != nullptr;
676}
677
678// Routing support implementation
679
680log_router& logger::get_router() {
681 if (!pimpl_) {
682 throw std::runtime_error("Logger not initialized");
683 }
684 std::shared_lock<std::shared_mutex> lock(pimpl_->router_mutex_);
685 return *pimpl_->router_;
686}
687
688const log_router& logger::get_router() const {
689 if (!pimpl_) {
690 throw std::runtime_error("Logger not initialized");
691 }
692 std::shared_lock<std::shared_mutex> lock(pimpl_->router_mutex_);
693 return *pimpl_->router_;
694}
695
696void logger::set_router(std::unique_ptr<log_router> router) {
697 if (pimpl_ && router) {
698 std::lock_guard<std::shared_mutex> lock(pimpl_->router_mutex_);
699 pimpl_->router_ = std::move(router);
700 }
701}
702
703bool logger::has_routing() const {
704 if (!pimpl_) {
705 return false;
706 }
707 std::shared_lock<std::shared_mutex> lock(pimpl_->router_mutex_);
708 // Check if router has any routes configured by checking if get_writers_for_log
709 // returns anything for a test entry
710 return pimpl_->router_ != nullptr;
711}
712
713// =========================================================================
714// Structured logging API implementation
715// =========================================================================
716
717structured_log_builder logger::log_structured(log_level level) {
718 // Get context fields from unified_log_context (thread-safe internally)
719 log_fields ctx_fields;
720 if (pimpl_ && !pimpl_->context_.empty()) {
721 ctx_fields = pimpl_->context_.to_fields();
722 }
723
724 // Capture by value since we need the fields to outlive this scope
726 level,
727 [this, level](log_entry&& entry) {
728 if (!pimpl_ || !meets_threshold(level, pimpl_->min_level_.load())) {
729 return;
730 }
731
732 // Apply filter if set
733 {
734 std::shared_lock<std::shared_mutex> filter_lock(pimpl_->filter_mutex_);
735 if (pimpl_->filter_) {
736 if (!pimpl_->filter_->should_log(entry)) {
737 return;
738 }
739 }
740 }
741
742 // Dispatch to writers
743 std::string file_str;
744 int line = 0;
745 std::string func_str;
746 if (entry.location) {
747 file_str = entry.location->file.to_string();
748 line = entry.location->line;
749 func_str = entry.location->function.to_string();
750 }
751
752 pimpl_->dispatch_to_writers(
753 entry.level,
754 entry.message.to_string(),
755 file_str,
756 line,
757 func_str,
758 entry
759 );
760 },
761 ctx_fields.empty() ? nullptr : &ctx_fields
762 );
763}
764
765// =========================================================================
766// Unified Context API implementation
767// =========================================================================
768
769unified_log_context& logger::context() {
770 // unified_log_context is thread-safe internally, no external locking needed
771 return pimpl_->context_;
772}
773
774const unified_log_context& logger::context() const {
775 return pimpl_->context_;
776}
777
778// Legacy context API (set_context, remove_context) removed.
779// Use context().set(key, value) and context().remove(key) instead.
780
781// =========================================================================
782// Real-time analysis implementation (optional, requires LOGGER_WITH_ANALYSIS)
783// =========================================================================
784
785#ifdef LOGGER_WITH_ANALYSIS
786void logger::set_realtime_analyzer(std::unique_ptr<analysis::realtime_log_analyzer> analyzer) {
787 if (pimpl_) {
788 std::lock_guard<std::shared_mutex> lock(pimpl_->analyzer_mutex_);
789 pimpl_->realtime_analyzer_ = std::move(analyzer);
790 }
791}
792
793analysis::realtime_log_analyzer* logger::get_realtime_analyzer() {
794 if (pimpl_) {
795 std::shared_lock<std::shared_mutex> lock(pimpl_->analyzer_mutex_);
796 return pimpl_->realtime_analyzer_.get();
797 }
798 return nullptr;
799}
800
801const analysis::realtime_log_analyzer* logger::get_realtime_analyzer() const {
802 if (pimpl_) {
803 std::shared_lock<std::shared_mutex> lock(pimpl_->analyzer_mutex_);
804 return pimpl_->realtime_analyzer_.get();
805 }
806 return nullptr;
807}
808
809bool logger::has_realtime_analysis() const {
810 if (pimpl_) {
811 std::shared_lock<std::shared_mutex> lock(pimpl_->analyzer_mutex_);
812 return pimpl_->realtime_analyzer_ != nullptr;
813 }
814 return false;
815}
816#endif // LOGGER_WITH_ANALYSIS
817
818// =========================================================================
819// Log sampling implementation
820// =========================================================================
821
822void logger::set_sampler(std::unique_ptr<sampling::log_sampler> sampler) {
823 if (pimpl_) {
824 std::lock_guard<std::shared_mutex> lock(pimpl_->sampler_mutex_);
825 pimpl_->sampler_ = std::move(sampler);
826 }
827}
828
829sampling::log_sampler* logger::get_sampler() {
830 if (pimpl_) {
831 std::shared_lock<std::shared_mutex> lock(pimpl_->sampler_mutex_);
832 return pimpl_->sampler_.get();
833 }
834 return nullptr;
835}
836
837const sampling::log_sampler* logger::get_sampler() const {
838 if (pimpl_) {
839 std::shared_lock<std::shared_mutex> lock(pimpl_->sampler_mutex_);
840 return pimpl_->sampler_.get();
841 }
842 return nullptr;
843}
844
845bool logger::has_sampling() const {
846 if (pimpl_) {
847 std::shared_lock<std::shared_mutex> lock(pimpl_->sampler_mutex_);
848 return pimpl_->sampler_ != nullptr && pimpl_->sampler_->is_enabled();
849 }
850 return false;
851}
852
853sampling::sampling_stats logger::get_sampling_stats() const {
854 if (pimpl_) {
855 std::shared_lock<std::shared_mutex> lock(pimpl_->sampler_mutex_);
856 if (pimpl_->sampler_) {
857 return pimpl_->sampler_->get_stats();
858 }
859 }
861}
862
863void logger::reset_sampling_stats() {
864 if (pimpl_) {
865 std::shared_lock<std::shared_mutex> lock(pimpl_->sampler_mutex_);
866 if (pimpl_->sampler_) {
867 pimpl_->sampler_->reset_stats();
868 }
869 }
870}
871
872} // namespace kcenon::logger
Base interface for all log writers and decorators.
std::atomic< size_t > emergency_buffer_used_
Definition logger.cpp:92
unified_log_context context_
Definition logger.cpp:83
void dispatch_to_writers(log_level level, const std::string &message, const std::string &file, int line, const std::string &function, const log_entry &entry)
Dispatch log to writers with routing support.
Definition logger.cpp:134
std::unique_ptr< log_filter_interface > filter_
Definition logger.cpp:71
std::unordered_map< std::string, std::shared_ptr< log_writer_interface > > named_writers_
Definition logger.cpp:67
std::unique_ptr< backends::integration_backend > backend_
Definition logger.cpp:69
impl(bool async, std::size_t buffer_size, std::unique_ptr< backends::integration_backend > backend)
Definition logger.cpp:95
std::unique_ptr< log_collector > collector_
Definition logger.cpp:70
std::shared_mutex sampler_mutex_
Definition logger.cpp:87
static constexpr size_t emergency_buffer_size_
Definition logger.cpp:90
std::shared_mutex router_mutex_
Definition logger.cpp:74
std::atomic< log_level > min_level_
Definition logger.cpp:65
std::shared_mutex writers_mutex_
Definition logger.cpp:68
char emergency_buffer_[emergency_buffer_size_]
Definition logger.cpp:91
std::unique_ptr< sampling::log_sampler > sampler_
Definition logger.cpp:86
std::shared_mutex filter_mutex_
Definition logger.cpp:72
std::unique_ptr< log_router > router_
Definition logger.cpp:73
std::vector< std::shared_ptr< log_writer_interface > > writers_
Definition logger.cpp:66
std::atomic< int > emergency_fd_
Definition logger.cpp:93
std::unique_ptr< impl > pimpl_
Definition logger.h:757
common::VoidResult stop()
Stop the logger.
Definition logger.cpp:245
common::VoidResult flush() override
Flush any buffered log messages (ILogger interface)
Definition logger.cpp:574
static result ok_value(const T &value)
Log router for directing messages to specific writers.
Definition log_router.h:49
Thread-safe log sampler with multiple strategy support.
Definition log_sampler.h:71
Fluent builder for creating structured log entries.
Unified interface for managing all types of logging context.
Asynchronous log collector using C++20 std::jthread kcenon.
Data structures for representing log entries and source locations kcenon.
Interface for log filters used by filtered_logger.
Log sampling implementation for high-volume scenarios kcenon.
Base interface for all log writers and decorators.
High-performance, thread-safe logging system with asynchronous capabilities.
VoidResult ok()
common::interfaces::log_level log_level
void record_message_logged(uint64_t time_ns)
Record a logged message.
LOGGER_SYSTEM_API logger_performance_stats g_logger_stats
Global logger metrics instance.
std::unordered_map< std::string, log_value > log_fields
Type alias for structured fields map.
Definition log_entry.h:75
common::VoidResult make_logger_void_result(logger_error_code code, const std::string &message="")
std::unique_ptr< log_writer_interface > log_writer_ptr
Type alias for writer unique pointer.
Real-time log analysis with anomaly detection.
Standalone integration backend implementation kcenon.
Log entry for analysis.
Definition analysis.cppm:43
log_level level
std::string message
std::string source_file
std::string function_name
int source_line
std::chrono::system_clock::time_point timestamp
Represents a single log entry with all associated metadata.
Definition log_entry.h:155
std::chrono::system_clock::time_point timestamp
Timestamp when the log entry was created.
Definition log_entry.h:175
Statistics about sampling behavior.
Conditionally enables thread_system integration when available.
Unified interface for managing all types of logging context.