Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
custom_writer_example.cpp

This example shows:

  1. How to inherit from thread_safe_writer for automatic thread-safety
  2. Implementing write_impl() and flush_impl() methods
  3. Using the writer with the logger system

Since v1.3.0, thread_safe_writer is the recommended base class for custom writers. It eliminates boilerplate mutex code and ensures consistent thread-safety.

// BSD 3-Clause License
// Copyright (c) 2025, 🍀☀🌕🌥 🌊
// See the LICENSE file in the project root for full license information.
#include <kcenon/common/interfaces/logger_interface.h>
#include <iostream>
#include <vector>
#include <map>
using namespace kcenon::logger;
namespace ci = kcenon::common::interfaces;
public:
memory_writer() = default;
std::string get_name() const override {
return "memory";
}
std::vector<std::string> get_entries() const {
std::lock_guard<std::mutex> lock(get_mutex());
return entries_;
}
size_t size() const {
std::lock_guard<std::mutex> lock(get_mutex());
return entries_.size();
}
void clear() {
std::lock_guard<std::mutex> lock(get_mutex());
entries_.clear();
}
protected:
{
std::string formatted = format_log_entry(entry);
// Store in memory - already protected by base class mutex
entries_.push_back(formatted);
}
// Nothing to flush for memory storage
}
private:
std::vector<std::string> entries_;
};
public:
// Initialize counters for each log level
for (int i = 0; i <= static_cast<int>(kcenon::common::interfaces::log_level::trace); ++i) {
counts_[static_cast<kcenon::common::interfaces::log_level>(i)] = 0;
}
}
std::string get_name() const override {
return "counted_console";
}
size_t get_count(kcenon::common::interfaces::log_level level) const {
std::lock_guard<std::mutex> lock(get_mutex());
auto it = counts_.find(level);
return (it != counts_.end()) ? it->second : 0;
}
size_t total_count() const {
std::lock_guard<std::mutex> lock(get_mutex());
size_t total = 0;
for (const auto& [level, count] : counts_) {
total += count;
}
return total;
}
void print_stats() const {
std::lock_guard<std::mutex> lock(get_mutex());
std::cout << "\n=== Log Statistics ===" << std::endl;
std::cout << "Fatal: " << counts_.at(kcenon::common::interfaces::log_level::fatal) << std::endl;
std::cout << "Error: " << counts_.at(kcenon::common::interfaces::log_level::error) << std::endl;
std::cout << "Warning: " << counts_.at(kcenon::common::interfaces::log_level::warning) << std::endl;
std::cout << "Info: " << counts_.at(kcenon::common::interfaces::log_level::info) << std::endl;
std::cout << "Debug: " << counts_.at(kcenon::common::interfaces::log_level::debug) << std::endl;
std::cout << "Trace: " << counts_.at(kcenon::common::interfaces::log_level::trace) << std::endl;
}
protected:
{
// Convert log_level from logger_system to common::interfaces
auto level = static_cast<kcenon::common::interfaces::log_level>(static_cast<int>(entry.level));
// Increment counter for this level
counts_[level]++;
// Format log entry
std::string formatted = format_log_entry(entry);
// Output to console with color based on level
if (use_color()) {
switch (level) {
case kcenon::common::interfaces::log_level::fatal:
case kcenon::common::interfaces::log_level::error:
std::cerr << "\033[31m" << formatted << "\033[0m" << std::endl;
break;
case kcenon::common::interfaces::log_level::warning:
std::cout << "\033[33m" << formatted << "\033[0m" << std::endl;
break;
default:
std::cout << formatted << std::endl;
break;
}
} else {
if (level <= kcenon::common::interfaces::log_level::error) {
std::cerr << formatted << std::endl;
} else {
std::cout << formatted << std::endl;
}
}
}
std::cout.flush();
std::cerr.flush();
}
private:
mutable std::map<kcenon::common::interfaces::log_level, size_t> counts_;
};
int main() {
std::cout << "=== Custom Writer Example (thread_safe_writer) ===" << std::endl;
std::cout << std::endl;
// Example 1: Memory Writer
std::cout << "--- Example 1: Memory Writer ---" << std::endl;
{
.with_min_level(kcenon::common::interfaces::log_level::info)
.add_writer("memory", std::make_unique<memory_writer>())
.build();
if (!result.has_value()) {
std::cerr << "Failed to create logger" << std::endl;
return 1;
}
auto logger = std::move(result.value());
// Log some messages
logger->log(ci::log_level::info, std::string("First message"));
logger->log(ci::log_level::warning, std::string("Second message"));
logger->log(ci::log_level::error, std::string("Third message"));
std::cout << "Logged 3 messages to memory writer" << std::endl;
}
std::cout << std::endl;
// Example 2: Counted Console Writer
std::cout << "--- Example 2: Counted Console Writer ---" << std::endl;
{
auto counted_writer = std::make_unique<counted_console_writer>();
auto* counted_ptr = counted_writer.get(); // Keep reference for stats
.with_min_level(kcenon::common::interfaces::log_level::debug)
.add_writer("counted", std::move(counted_writer))
.build();
if (!result.has_value()) {
std::cerr << "Failed to create logger" << std::endl;
return 1;
}
auto logger = std::move(result.value());
// Log messages at different levels
logger->log(ci::log_level::debug, std::string("Debug message 1"));
logger->log(ci::log_level::debug, std::string("Debug message 2"));
logger->log(ci::log_level::info, std::string("Info message"));
logger->log(ci::log_level::warning, std::string("Warning message"));
logger->log(ci::log_level::error, std::string("Error message"));
// Print statistics
counted_ptr->print_stats();
}
std::cout << std::endl;
std::cout << "=== Custom Writer Example Complete ===" << std::endl;
return 0;
}
int main()
A console writer that counts messages per log level.
kcenon::common::VoidResult flush_impl() override
Implementation of flush operation (override in derived classes)
std::string get_name() const override
kcenon::common::VoidResult write_entry_impl(const log_entry &entry) override
Implementation of structured write operation (override in derived classes)
size_t total_count() const
Get total message count.
void print_stats() const
Print statistics summary.
size_t get_count(kcenon::common::interfaces::log_level level) const
Get count for a specific log level.
std::map< kcenon::common::interfaces::log_level, size_t > counts_
std::string format_log_entry(const log_entry &entry) const
Format a log entry using the current formatter.
bool use_color() const
Get current color output setting.
Builder pattern for logger construction with validation.
logger_builder & with_min_level(log_level level)
result< std::unique_ptr< logger > > build()
logger_builder & add_writer(const std::string &name, log_writer_ptr writer)
Add a writer to the logger.
Base class providing automatic thread-safety for writer implementations.
std::mutex & get_mutex() const
Access the writer mutex for extended operations.
A custom writer that stores log entries in memory.
kcenon::common::VoidResult flush_impl() override
Implementation of flush operation.
std::vector< std::string > entries_
size_t size() const
Get count of stored entries.
kcenon::common::VoidResult write_entry_impl(const log_entry &entry) override
Implementation of write operation.
memory_writer()=default
std::vector< std::string > get_entries() const
Get all stored log entries.
std::string get_name() const override
void clear()
Clear all stored entries.
Console writer for logging to stdout/stderr.
JSON formatter for structured logging kcenon.
Data structures for representing log entries and source locations kcenon.
Builder pattern implementation for flexible logger configuration kcenon.
VoidResult ok()
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
Thread-safe base class for writer implementations kcenon.