Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
high_performance_async_writer.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
6#include <algorithm>
7
8namespace kcenon::logger::async {
9
11 log_writer_ptr wrapped_writer,
12 const config& cfg)
13 : config_(cfg)
14 , wrapped_writer_(std::move(wrapped_writer)) {
15
16 if (!wrapped_writer_) {
17 throw std::invalid_argument("Wrapped writer cannot be null");
18 }
19
20 // Initialize memory pool if enabled
22 memory_pool_ = std::make_unique<memory::object_pool<memory::log_entry_pool::pooled_log_entry>>(
23 config_.pool_config);
24 }
25
26 // Initialize batch processor if enabled
28 batch_processor_ = make_batch_processor(
29 log_writer_ptr(wrapped_writer_.release()),
30 config_.batch_config);
31 }
32}
33
37
39 bool expected = false;
40 if (!running_.compare_exchange_strong(expected, true)) {
41 return false; // Already running
42 }
43
44 if (batch_processor_) {
45 return batch_processor_->start();
46 }
47
48 return true;
49}
50
51void high_performance_async_writer::stop(bool flush_remaining) {
52 if (!running_.exchange(false)) {
53 return; // Already stopped
54 }
55
56 if (batch_processor_) {
57 batch_processor_->stop(flush_remaining);
58 } else if (flush_remaining && wrapped_writer_) {
59 wrapped_writer_->flush();
60 }
61}
62
64
65 const auto start_time = std::chrono::steady_clock::now();
66
67 if (!running_.load(std::memory_order_relaxed)) {
68 return write_direct(entry);
69 }
70
71 stats_.total_writes.fetch_add(1, std::memory_order_relaxed);
72
73 // Use batch processor if available
74 if (batch_processor_) {
75 // Convert log_level from logger_system to common::interfaces
76 auto level = static_cast<common::interfaces::log_level>(static_cast<int>(entry.level));
77
78 // Construct batch_entry directly with to_string() rvalues to avoid copies
80 level,
81 entry.message.to_string(),
82 entry.location ? entry.location->file.to_string() : std::string{},
83 entry.location ? entry.location->line : 0,
84 entry.location ? entry.location->function.to_string() : std::string{},
85 entry.timestamp);
86
87 if (batch_processor_->add_entry(std::move(batch_entry))) {
88 const auto end_time = std::chrono::steady_clock::now();
89 const auto latency = end_time - start_time;
90 update_stats(true, latency);
91 return common::ok();
92 } else {
93 stats_.dropped_writes.fetch_add(1, std::memory_order_relaxed);
94 // Fall back to direct write
95 return write_direct(entry);
96 }
97 }
98
99 // Direct async write (fallback mode)
100 return write_direct(entry);
101}
102
104 if (batch_processor_) {
105 batch_processor_->flush();
106 } else if (wrapped_writer_) {
107 return wrapped_writer_->flush();
108 }
109 return common::ok();
110}
111
113 if (!running_.load(std::memory_order_relaxed)) {
114 return false;
115 }
116
117 if (batch_processor_) {
118 return batch_processor_->is_healthy();
119 }
120
121 return wrapped_writer_ && wrapped_writer_->is_healthy();
122}
123
125 const std::string base_name = wrapped_writer_ ? wrapped_writer_->get_name() : "unknown";
126 return "high_perf_async_" + base_name;
127}
128
130 // Color setting is now handled by formatter, not writer interface
131 // This method is kept for backward compatibility but is deprecated
132 (void)use_color; // Suppress unused parameter warning
133}
134
136 if (batch_processor_) {
137 const auto queue_size = batch_processor_->get_queue_size();
138 const auto max_size = config_.queue_size;
139 return static_cast<double>(queue_size) / max_size;
140 }
141 return 0.0;
142}
143
145 if (batch_processor_) {
146 return &batch_processor_->get_stats();
147 }
148 return nullptr;
149}
150
152
153 if (!wrapped_writer_) {
154 return make_logger_void_result(logger_error_code::writer_not_available, "No wrapped writer available");
155 }
156
157 const auto start_time = std::chrono::steady_clock::now();
158 auto result = wrapped_writer_->write(entry);
159 const auto end_time = std::chrono::steady_clock::now();
160
161 const auto latency = end_time - start_time;
162 update_stats(result.is_ok(), latency);
163
164 return result;
165}
166
167void high_performance_async_writer::update_stats(bool success, std::chrono::nanoseconds latency) {
168 if (success) {
169 stats_.successful_writes.fetch_add(1, std::memory_order_relaxed);
170 }
171
172 // Update average latency using exponential moving average
173 const double latency_us = std::chrono::duration_cast<std::chrono::microseconds>(latency).count();
174 const double alpha = 0.1; // Smoothing factor
175 const double current_avg = stats_.average_latency_us.load(std::memory_order_relaxed);
176 const double new_avg = alpha * latency_us + (1.0 - alpha) * current_avg;
177 stats_.average_latency_us.store(new_avg, std::memory_order_relaxed);
178
179 // Update throughput
180 const auto now = std::chrono::steady_clock::now();
181 const auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - stats_.start_time).count();
182 if (elapsed > 0) {
183 const auto total_writes = stats_.total_writes.load(std::memory_order_relaxed);
184 const double throughput = static_cast<double>(total_writes) / elapsed;
185 stats_.throughput_per_second.store(throughput, std::memory_order_relaxed);
186 }
187}
188
190 const queued_log_entry& entry) const {
192 entry.level,
193 entry.message,
194 entry.file,
195 entry.line,
196 entry.function,
197 entry.timestamp);
198}
199
200std::unique_ptr<high_performance_async_writer> make_high_performance_async_writer(
201 log_writer_ptr writer,
203 return std::make_unique<high_performance_async_writer>(std::move(writer), cfg);
204}
205
206} // namespace kcenon::logger::async
void set_use_color(bool use_color) override
Set whether to use color output.
double get_queue_utilization() const
Get current queue utilization.
std::string get_name() const override
Get the name of this writer.
high_performance_async_writer(log_writer_ptr wrapped_writer, const config &cfg=config{})
Constructor.
bool is_healthy() const override
Check if the writer is healthy.
void update_stats(bool success, std::chrono::nanoseconds latency)
Update performance statistics.
common::VoidResult flush() override
Flush all pending messages.
const batch_processor::processing_stats * get_batch_stats() const
Get batch processor statistics if enabled.
common::VoidResult write(const log_entry &entry) override
Write a log entry asynchronously.
void stop(bool flush_remaining=true)
Stop the async writer.
batch_processor::batch_entry to_batch_entry(const queued_log_entry &entry) const
Convert to batch entry format.
common::VoidResult write_direct(const log_entry &entry)
Write directly to the underlying writer (fallback mode)
bool use_color() const
Get current color output setting.
std::string to_string() const
Convert to std::string.
High-performance asynchronous writer using lock-free queue and memory pooling.
VoidResult ok()
std::unique_ptr< high_performance_async_writer > make_high_performance_async_writer(log_writer_ptr writer, const high_performance_async_writer::config &cfg)
Factory function to create a high-performance async writer.
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.
Batch entry structure.
Configuration for the high-performance async writer.
Log entry optimized for high-performance queuing.
std::string function
std::chrono::system_clock::time_point timestamp
std::string file
int line
common::interfaces::log_level level
std::string message
Represents a single log entry with all associated metadata.
Definition log_entry.h:155
std::optional< source_location > location
Optional source code location information.
Definition log_entry.h:183
log_level level
Severity level of the log message.
Definition log_entry.h:162
small_string_256 message
The actual log message.
Definition log_entry.h:169
std::chrono::system_clock::time_point timestamp
Timestamp when the log entry was created.
Definition log_entry.h:175