Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
decorator_usage.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
23#include <kcenon/logger/builders/writer_builder.h>
29
30#ifdef LOGGER_WITH_ENCRYPTION
31#include <kcenon/logger/security/secure_key.h>
33#endif
34
35#include <iostream>
36#include <memory>
37#include <thread>
38#include <chrono>
39
40using namespace kcenon::logger;
41namespace common = kcenon::common;
42using log_level = common::interfaces::log_level;
43
48public:
49 explicit level_filter(log_level min_level) : min_level_(min_level) {}
50
51 bool should_log(const log_entry& entry) const override {
52 return entry.level >= min_level_;
53 }
54
55 std::string get_name() const override {
56 return "level_filter";
57 }
58
59private:
60 log_level min_level_;
61};
62
67public:
68 explicit content_filter(std::string keyword) : keyword_(std::move(keyword)) {}
69
70 bool should_log(const log_entry& entry) const override {
71 std::string msg(entry.message.data(), entry.message.size());
72 return msg.find(keyword_) != std::string::npos;
73 }
74
75 std::string get_name() const override {
76 return "content_filter";
77 }
78
79private:
80 std::string keyword_;
81};
82
83void print_section(const std::string& title) {
84 std::cout << "\n" << std::string(60, '=') << "\n";
85 std::cout << title << "\n";
86 std::cout << std::string(60, '=') << "\n";
87}
88
96 print_section("Example 1: Core Writers (No Decorators)");
97
98 std::cout << "\n1.1 File Writer:\n";
99 auto file_writer = writer_builder()
100 .file("basic.log")
101 .build();
102 std::cout << " Created: " << file_writer->get_name() << "\n";
103 std::cout << " Use case: Direct file output, simplest form\n";
104
105 std::cout << "\n1.2 Console Writer:\n";
106 auto console_writer = writer_builder()
107 .console()
108 .build();
109 std::cout << " Created: " << console_writer->get_name() << "\n";
110 std::cout << " Use case: Development, debugging, immediate visual feedback\n";
111
112 std::cout << "\nKey Points:\n";
113 std::cout << " • Core writers provide the actual I/O functionality\n";
114 std::cout << " • No buffering, no async - synchronous and immediate\n";
115 std::cout << " • Best for: Simple use cases, testing, development\n";
116}
117
124 print_section("Example 2: Single Decorator Usage");
125
126 std::cout << "\n2.1 Async Writer (Performance):\n";
127 auto async_log_writer = writer_builder()
128 .file("async.log")
129 .async(10000) // Queue size: 10000 entries
130 .build();
131 std::cout << " Created: " << async_log_writer->get_name() << "\n";
132 std::cout << " Benefit: Non-blocking writes, background thread processing\n";
133 std::cout << " Trade-off: Slight delay in writing, memory for queue\n";
134 std::cout << " Best for: High-throughput applications\n";
135
136 // Start and stop async writer
137 if (auto* async_w = dynamic_cast<async_writer*>(async_log_writer.get())) {
138 async_w->start();
139 std::cout << " Status: Started background thread\n";
140 async_w->stop();
141 }
142
143 std::cout << "\n2.2 Buffered Writer (I/O Efficiency):\n";
144 auto buffered_writer = writer_builder()
145 .file("buffered.log")
146 .buffered(100) // Buffer up to 100 entries
147 .build();
148 std::cout << " Created: " << buffered_writer->get_name() << "\n";
149 std::cout << " Benefit: Reduces I/O operations by batching\n";
150 std::cout << " Trade-off: Logs may be delayed until buffer fills\n";
151 std::cout << " Best for: Moderate throughput, reducing disk I/O\n";
152
153 std::cout << "\n2.3 Filtered Writer (Selective Logging):\n";
154 auto filter = std::make_unique<level_filter>(log_level::warning);
155 auto filtered_writer = writer_builder()
156 .file("warnings.log")
157 .filtered(std::move(filter))
158 .build();
159 std::cout << " Created: " << filtered_writer->get_name() << "\n";
160 std::cout << " Benefit: Only writes logs meeting criteria (e.g., WARNING+)\n";
161 std::cout << " Trade-off: Filtering overhead (usually negligible)\n";
162 std::cout << " Best for: Separate error logs, compliance logging\n";
163
164#ifdef LOGGER_WITH_ENCRYPTION
165 std::cout << "\n2.4 Encrypted Writer (Security):\n";
166 using namespace kcenon::logger::security;
167 auto key_result = secure_key_storage::generate_key(32);
168 if (key_result.is_ok()) {
169 auto encrypted_writer = writer_builder()
170 .file("secure.log.enc")
171 .encrypted(std::move(key_result.value()))
172 .build();
173 std::cout << " Created: " << encrypted_writer->get_name() << "\n";
174 std::cout << " Benefit: AES-256-GCM encryption for sensitive data\n";
175 std::cout << " Trade-off: CPU overhead for encryption\n";
176 std::cout << " Best for: Compliance (GDPR, PCI DSS), sensitive logs\n";
177 }
178#else
179 std::cout << "\n2.4 Encrypted Writer: Skipped (encryption not available)\n";
180#endif
181
182 std::cout << "\nKey Points:\n";
183 std::cout << " • Each decorator adds specific functionality\n";
184 std::cout << " • Single decorators are easier to reason about\n";
185 std::cout << " • Combine multiple decorators for complex scenarios\n";
186}
187
195 print_section("Example 3: Multiple Decorator Composition");
196
197 std::cout << "\n3.1 Buffered + Async (Common Pattern):\n";
198 auto buffered_async = writer_builder()
199 .file("app.log")
200 .buffered(500) // Buffer first
201 .async(20000) // Then async
202 .build();
203 std::cout << " Created: " << buffered_async->get_name() << "\n";
204 std::cout << " Order: file → buffered(500) → async(20000)\n";
205 std::cout << " Rationale:\n";
206 std::cout << " 1. Buffering reduces I/O operations\n";
207 std::cout << " 2. Async provides non-blocking writes\n";
208 std::cout << " Best for: High-performance production applications\n";
209
210 if (auto* async_w = dynamic_cast<async_writer*>(buffered_async.get())) {
211 async_w->start();
212 async_w->stop();
213 }
214
215 std::cout << "\n3.2 Filtered + Buffered + Async (Error Log):\n";
216 auto error_filter = std::make_unique<level_filter>(log_level::error);
217 auto filtered_buffered_async = writer_builder()
218 .file("errors.log")
219 .filtered(std::move(error_filter)) // Filter first
220 .buffered(100) // Then buffer
221 .async(5000) // Then async
222 .build();
223 std::cout << " Created: " << filtered_buffered_async->get_name() << "\n";
224 std::cout << " Order: file → filtered → buffered(100) → async(5000)\n";
225 std::cout << " Rationale:\n";
226 std::cout << " 1. Filter early to reduce processing\n";
227 std::cout << " 2. Buffer to batch error logs\n";
228 std::cout << " 3. Async for non-blocking error logging\n";
229 std::cout << " Best for: Separate error logs with filtering\n";
230
231 if (auto* async_w = dynamic_cast<async_writer*>(filtered_buffered_async.get())) {
232 async_w->start();
233 async_w->stop();
234 }
235
236#ifdef LOGGER_WITH_ENCRYPTION
237 std::cout << "\n3.3 Buffered + Encrypted + Async (Secure High-Performance):\n";
238 using namespace kcenon::logger::security;
239 auto key_result = secure_key_storage::generate_key(32);
240 if (key_result.is_ok()) {
241 auto secure_writer = writer_builder()
242 .file("secure.log.enc")
243 .buffered(200) // Buffer first
244 .encrypted(std::move(key_result.value())) // Then encrypt
245 .async(10000) // Then async
246 .build();
247 std::cout << " Created: " << secure_writer->get_name() << "\n";
248 std::cout << " Order: file → buffered(200) → encrypted → async(10000)\n";
249 std::cout << " Rationale:\n";
250 std::cout << " 1. Buffer to reduce encryption overhead\n";
251 std::cout << " 2. Encrypt for security (batches are encrypted together)\n";
252 std::cout << " 3. Async to prevent encryption from blocking\n";
253 std::cout << " Best for: Secure, high-performance logging\n";
254
255 if (auto* async_w = dynamic_cast<async_writer*>(secure_writer.get())) {
256 async_w->start();
257 async_w->stop();
258 }
259 }
260#else
261 std::cout << "\n3.3 Encrypted combination: Skipped (encryption not available)\n";
262#endif
263
264 std::cout << "\nDecorator Order Principle:\n";
265 std::cout << " Core Writer → Filtering → Buffering → Encryption → Thread-Safety → Async\n";
266 std::cout << "\nWhy this order?\n";
267 std::cout << " 1. Filter early: Reduce work for downstream decorators\n";
268 std::cout << " 2. Buffer before encrypt: Amortize encryption cost\n";
269 std::cout << " 3. Thread-safe before async: Ensure consistency\n";
270 std::cout << " 4. Async outermost: Maximize non-blocking benefits\n";
271}
272
279 print_section("Example 4: Performance Patterns");
280
281 std::cout << "\n4.1 High-Throughput Pattern:\n";
282 std::cout << " Configuration: file → buffered(1000) → async(50000)\n";
283 std::cout << " Throughput: ~4M messages/second (single thread)\n";
284 std::cout << " Latency: ~148ns average\n";
285 std::cout << " Use case: Logging-heavy applications, analytics\n";
286
287 std::cout << "\n4.2 Low-Latency Pattern:\n";
288 std::cout << " Configuration: file → async(small_queue)\n";
289 std::cout << " Throughput: Lower than buffered\n";
290 std::cout << " Latency: Minimal buffering delay\n";
291 std::cout << " Use case: Real-time systems, trading platforms\n";
292
293 std::cout << "\n4.3 Balanced Pattern:\n";
294 std::cout << " Configuration: file → buffered(500) → async(20000)\n";
295 std::cout << " Throughput: Good (millions of messages/second)\n";
296 std::cout << " Latency: Acceptable for most applications\n";
297 std::cout << " Use case: General production applications\n";
298
299 std::cout << "\n4.4 Security-First Pattern:\n";
300 std::cout << " Configuration: file → filtered → encrypted → buffered → async\n";
301 std::cout << " Throughput: Moderate (encryption overhead)\n";
302 std::cout << " Latency: Higher due to encryption\n";
303 std::cout << " Use case: Compliance-critical applications\n";
304
305 std::cout << "\nPerformance Tips:\n";
306 std::cout << " • Larger buffers = fewer I/O ops but more memory\n";
307 std::cout << " • Larger async queues = better burst handling\n";
308 std::cout << " • Encryption adds ~10-20% CPU overhead\n";
309 std::cout << " • Filtering early reduces downstream processing\n";
310}
311
318 print_section("Example 5: Production Scenarios");
319
320 logger log;
321
322 std::cout << "\n5.1 Web Application Logging:\n";
323 std::cout << " Requirements: High throughput, separate error logs, async\n";
324
325 // Main application log
326 auto main_log = writer_builder()
327 .file("app.log")
328 .buffered(500)
329 .async(20000)
330 .build();
331 std::cout << " Main log: " << main_log->get_name() << "\n";
332
333 if (auto* async_w = dynamic_cast<async_writer*>(main_log.get())) {
334 async_w->start();
335 }
336 log.add_writer("main", std::move(main_log));
337
338 // Error log (separate file, errors only)
339 auto error_filter = std::make_unique<level_filter>(log_level::error);
340 auto error_log = writer_builder()
341 .file("errors.log")
342 .filtered(std::move(error_filter))
343 .async()
344 .build();
345 std::cout << " Error log: " << error_log->get_name() << "\n";
346
347 if (auto* async_w = dynamic_cast<async_writer*>(error_log.get())) {
348 async_w->start();
349 }
350 log.add_writer("errors", std::move(error_log));
351
352 // Console for development
353 auto console = writer_builder()
354 .console()
355 .build();
356 std::cout << " Console: " << console->get_name() << "\n";
357 log.add_writer("console", std::move(console));
358
359 std::cout << "\n5.2 Microservice with Observability:\n";
360 std::cout << " Requirements: Structured logs, filtering, async\n";
361 // In real scenario, would use structured logging and OTLP writer
362 std::cout << " Pattern: file → filtered → buffered → async\n";
363 std::cout << " Additional: OTLP writer for OpenTelemetry export\n";
364
365#ifdef LOGGER_WITH_ENCRYPTION
366 std::cout << "\n5.3 Healthcare/Financial Application:\n";
367 std::cout << " Requirements: HIPAA/PCI compliance, encryption, audit trail\n";
368 using namespace kcenon::logger::security;
369 auto key_result = secure_key_storage::generate_key(32);
370 if (key_result.is_ok()) {
371 auto secure_log = writer_builder()
372 .file("audit.log.enc")
373 .buffered(100)
374 .encrypted(std::move(key_result.value()))
375 .async()
376 .build();
377 std::cout << " Audit log: " << secure_log->get_name() << "\n";
378 std::cout << " Pattern: file → buffered → encrypted → async\n";
379
380 if (auto* async_w = dynamic_cast<async_writer*>(secure_log.get())) {
381 async_w->start();
382 }
383 log.add_writer("audit", std::move(secure_log));
384 }
385#else
386 std::cout << "\n5.3 Secure logging: Skipped (encryption not available)\n";
387#endif
388
389 // Log some messages
390 std::cout << "\nTesting the setup:\n";
391 log.log(log_level::info, std::string("User logged in"));
392 log.log(log_level::warning, std::string("Session expiring soon"));
393 log.log(log_level::error, std::string("Payment processing failed"));
394
395 std::cout << " INFO: → main log, console\n";
396 std::cout << " WARNING: → main log, console\n";
397 std::cout << " ERROR: → main log, errors log, console\n";
398
399 log.flush();
400 std::cout << "\nProduction Best Practices:\n";
401 std::cout << " 1. Always use async for production\n";
402 std::cout << " 2. Separate error logs for quick triage\n";
403 std::cout << " 3. Buffer sizes: 100-1000 entries\n";
404 std::cout << " 4. Async queue: 10000-50000 entries\n";
405 std::cout << " 5. Monitor queue utilization\n";
406 std::cout << " 6. Always call flush() on shutdown\n";
407}
408
415 print_section("Example 6: Custom Filtering Patterns");
416
417 std::cout << "\n6.1 Content-Based Filtering:\n";
418 auto content_filter_ptr = std::make_unique<content_filter>("database");
419 auto db_log = writer_builder()
420 .file("database_events.log")
421 .filtered(std::move(content_filter_ptr))
422 .buffered(50)
423 .async()
424 .build();
425 std::cout << " Created: " << db_log->get_name() << "\n";
426 std::cout << " Filter: Only logs containing 'database'\n";
427 std::cout << " Use case: Component-specific logging\n";
428
429 if (auto* async_w = dynamic_cast<async_writer*>(db_log.get())) {
430 async_w->start();
431 async_w->stop();
432 }
433
434 std::cout << "\n6.2 Level-Based Filtering:\n";
435 std::cout << " Critical errors only:\n";
436 auto critical_filter = std::make_unique<level_filter>(log_level::critical);
437 auto critical_log = writer_builder()
438 .file("critical.log")
439 .filtered(std::move(critical_filter))
440 .build();
441 std::cout << " Created: " << critical_log->get_name() << "\n";
442
443 std::cout << "\nFiltering Strategies:\n";
444 std::cout << " • By level: Common, efficient\n";
445 std::cout << " • By content: Flexible, component-specific\n";
446 std::cout << " • By custom logic: Implement log_filter_interface\n";
447 std::cout << " • Composite filters: Combine multiple filters (AND/OR)\n";
448}
449
456 print_section("Example 7: Migration from Manual Nesting");
457
458 std::cout << "\nOLD (Deprecated - Manual Nesting):\n";
459 std::cout << " auto writer = std::make_unique<async_writer>(\n";
460 std::cout << " std::make_unique<buffered_writer>(\n";
461 std::cout << " std::make_unique<file_writer>(\"app.log\"),\n";
462 std::cout << " 500),\n";
463 std::cout << " 20000);\n";
464 std::cout << "\nProblems:\n";
465 std::cout << " ✗ Verbose and error-prone\n";
466 std::cout << " ✗ Nesting order is unclear\n";
467 std::cout << " ✗ Hard to modify (add/remove decorators)\n";
468
469 std::cout << "\nNEW (Recommended - Writer Builder):\n";
470 std::cout << " auto writer = writer_builder()\n";
471 std::cout << " .file(\"app.log\")\n";
472 std::cout << " .buffered(500)\n";
473 std::cout << " .async(20000)\n";
474 std::cout << " .build();\n";
475 std::cout << "\nBenefits:\n";
476 std::cout << " ✓ Clear, self-documenting\n";
477 std::cout << " ✓ Type-safe at compile time\n";
478 std::cout << " ✓ Easy to modify\n";
479 std::cout << " ✓ Follows decorator order convention\n";
480
481 auto writer = writer_builder()
482 .file("migration_example.log")
483 .buffered(500)
484 .async(20000)
485 .build();
486
487 std::cout << "\nResult: " << writer->get_name() << "\n";
488
489 if (auto* async_w = dynamic_cast<async_writer*>(writer.get())) {
490 async_w->start();
491 async_w->stop();
492 }
493
494 std::cout << "\nMigration Steps:\n";
495 std::cout << " 1. Identify manual decorator nesting in your code\n";
496 std::cout << " 2. Replace with writer_builder() calls\n";
497 std::cout << " 3. Test thoroughly (behavior should be identical)\n";
498 std::cout << " 4. Enjoy improved readability and maintainability\n";
499}
500
501int main() {
502 std::cout << "Comprehensive Decorator Pattern Usage Examples\n";
503 std::cout << std::string(60, '=') << "\n";
504 std::cout << "\nThis example covers all decorator functionality:\n";
505 std::cout << " • Core writers (file, console)\n";
506 std::cout << " • All decorators (async, buffered, filtered, encrypted)\n";
507 std::cout << " • Decorator composition and order\n";
508 std::cout << " • Performance patterns and trade-offs\n";
509 std::cout << " • Real-world production scenarios\n";
510 std::cout << " • Migration from manual nesting\n";
511
512 try {
520
521 print_section("Summary: Decorator Order Convention");
522 std::cout << "\nRecommended Order (innermost to outermost):\n";
523 std::cout << " 1. Core Writer (file/console) - The actual I/O\n";
524 std::cout << " 2. Filtering - Reduce work early\n";
525 std::cout << " 3. Buffering - Batch for efficiency\n";
526 std::cout << " 4. Encryption - Encrypt batches\n";
527 std::cout << " 5. Thread-Safety - Ensure consistency\n";
528 std::cout << " 6. Async - Outermost for maximum non-blocking benefit\n";
529
530 std::cout << "\nQuick Reference:\n";
531 std::cout << " • High throughput: .buffered(1000).async(50000)\n";
532 std::cout << " • Low latency: .async(small_queue)\n";
533 std::cout << " • Secure: .buffered().encrypted().async()\n";
534 std::cout << " • Filtered: .filtered(filter).buffered().async()\n";
535
536 print_section("All Examples Completed Successfully");
537 std::cout << "\nFor more details, see:\n";
538 std::cout << " • README.md - Quick start and examples\n";
539 std::cout << " • docs/guides/DECORATOR_MIGRATION.md - Migration guide\n";
540 std::cout << " • examples/writer_builder_example.cpp - Builder examples\n";
541
542 } catch (const std::exception& e) {
543 std::cerr << "\nError: " << e.what() << "\n";
544 return 1;
545 }
546
547 return 0;
548}
Asynchronous wrapper for log writers.
Custom filter that filters by message content.
content_filter(std::string keyword)
std::string get_name() const override
Get the name of this filter.
std::string keyword_
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Asynchronous wrapper for log writers.
Decorator that buffers log entries before writing to wrapped writer.
Core console writer for logging to stdout/stderr.
std::string get_name() const override
Get writer name.
std::string get_name() const override
Get the name of this writer.
Decorator that encrypts log data before writing.
Core file writer for logging to files.
Definition file_writer.h:44
std::string get_name() const override
Get writer name.
Definition file_writer.h:89
Decorator that applies a filter to a wrapped writer.
std::string get_name() const override
Get the name of this writer.
Filter logs by minimum level.
Definition log_filter.h:72
common::VoidResult add_writer(log_writer_ptr writer)
Definition logger.cpp:265
common::VoidResult log(common::interfaces::log_level level, const std::string &message) override
Log a message with specified level (ILogger interface)
Definition logger.cpp:378
common::VoidResult flush() override
Flush any buffered log messages (ILogger interface)
Definition logger.cpp:574
const char * data() const noexcept
Get data pointer.
size_t size() const noexcept
Get size.
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
level_filter(log_level min_level)
std::string get_name() const override
Get the name of this filter.
log_level min_level_
Console writer for logging to stdout/stderr.
void example_single_decorators()
Example 2: Single Decorator Usage.
void print_section(const std::string &title)
void example_core_writers()
Example 1: Core Writers (No Decorators)
void example_performance_patterns()
Example 4: Performance Comparison.
void example_custom_filtering()
Example 6: Custom Filtering Patterns.
int main()
void example_migration_patterns()
Example 7: Migration from Manual Nesting.
void example_multiple_decorators()
Example 3: Multiple Decorator Composition.
void example_production_scenarios()
Example 5: Real-World Production Scenarios.
File writer for logging to files with optional buffering.
Interface for log filters used by filtered_logger.
High-performance, thread-safe logging system with asynchronous capabilities.
common::interfaces::log_level log_level
RAII wrapper for encryption keys with secure memory management.
Represents a single log entry with all associated metadata.
Definition log_entry.h:155
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