Logger System 1.0.0
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
console_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
11#include <iostream>
12#include <iomanip>
13#include <cstdlib>
14#include <sstream>
15#include <thread>
16
17#ifdef _WIN32
18#include <windows.h>
19#include <io.h>
20#else
21#include <unistd.h>
22#endif
23
24namespace kcenon::logger {
25
27 bool auto_detect_color,
28 std::unique_ptr<log_formatter_interface> formatter)
29 : use_stderr_(use_stderr)
30 , formatter_(formatter ? std::move(formatter) : std::make_unique<timestamp_formatter>()) {
31 if (auto_detect_color) {
33 } else {
34 // Apply color setting to formatter
35 auto opts = formatter_->get_options();
36 opts.use_colors = use_color_;
37 formatter_->set_options(opts);
38 }
39}
40
44
46 std::lock_guard<std::mutex> lock(mutex_);
48 // Convert logger_system::log_level to common::interfaces::log_level for comparison
49 auto level = static_cast<common::interfaces::log_level>(static_cast<int>(entry.level));
50
51 // Route error/fatal to stderr; everything less severe to stdout.
52 // log_level values are ordered by severity (trace=0 ... fatal=5),
53 // so >= error selects the high-severity bucket.
54 auto& stream = (use_stderr_ || level >= common::interfaces::log_level::error)
55 ? std::cerr : std::cout;
56
57 if (use_color()) {
58 // Simple color mapping based on level
59 switch (level) {
60 case common::interfaces::log_level::fatal:
61 case common::interfaces::log_level::error:
62 stream << "\033[31m"; // Red
63 break;
64 case common::interfaces::log_level::warning:
65 stream << "\033[33m"; // Yellow
66 break;
67 case common::interfaces::log_level::info:
68 stream << "\033[32m"; // Green
69 break;
70 case common::interfaces::log_level::debug:
71 stream << "\033[36m"; // Cyan
72 break;
73 case common::interfaces::log_level::trace:
74 stream << "\033[37m"; // White
75 break;
76 default:
77 break;
78 }
79 }
80
81 std::string formatted = format_entry(entry);
82
83 // Append tamper-evident signature (Issue #612) when configured.
84 // Color reset is emitted first so the signature is never colorized
85 // and stays machine-readable by downstream collectors.
86 stream << formatted;
87
88 if (use_color()) {
89 stream << "\033[0m"; // Reset color
90 }
91
94 *integrity_policy_, formatted);
95 }
96
97 stream << '\n';
98
99 // Verify stream state
100 return utils::check_stream_state(stream, "console write");
102}
103
105 std::lock_guard<std::mutex> lock(mutex_);
107 std::cout.flush();
108 std::cerr.flush();
109
110 if (std::cout.fail() || std::cerr.fail()) {
111 return make_logger_void_result(logger_error_code::flush_timeout, "Console flush failed");
112 }
113
114 return common::ok();
116}
117
119 return std::cout.good() && std::cerr.good();
120}
121
122void console_writer::set_use_stderr(bool use_stderr) {
123 std::lock_guard<std::mutex> lock(mutex_);
124 use_stderr_ = use_stderr;
125}
126
127void console_writer::set_use_color(bool use_color) {
129 if (formatter_) {
130 auto opts = formatter_->get_options();
131 opts.use_colors = use_color_;
132 formatter_->set_options(opts);
133 }
134}
135
137 return use_color_;
138}
139
141 std::shared_ptr<security::integrity_policy> policy) {
142 std::lock_guard<std::mutex> lock(mutex_);
143 integrity_policy_ = std::move(policy);
144}
145
146std::string console_writer::format_entry(const log_entry& entry) const {
147 if (!formatter_) {
148 // Fallback if formatter is somehow null
149 return entry.message.to_string();
150 }
151 return formatter_->format(entry);
152}
153
155#ifdef _WIN32
156 // Check if running in Windows Terminal or if ANSI is enabled
157 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
158 if (hOut == INVALID_HANDLE_VALUE) {
159 return false;
160 }
161
162 DWORD dwMode = 0;
163 if (!GetConsoleMode(hOut, &dwMode)) {
164 return false;
165 }
166
167 // Check for ENABLE_VIRTUAL_TERMINAL_PROCESSING flag
168 return (dwMode & 0x0004) != 0;
169#else
170 // Check if output is to a terminal and TERM is set
171 const char* term = std::getenv("TERM");
172 return isatty(STDOUT_FILENO) && term && std::string(term) != "dumb";
173#endif
174}
175
176} // namespace kcenon::logger
console_writer(bool use_stderr=false, bool auto_detect_color=true, std::unique_ptr< log_formatter_interface > formatter=nullptr)
Constructor.
bool is_healthy() const override
Check if writer is healthy.
bool use_color() const
Get current color output setting.
bool is_color_supported() const
Check if terminal supports color.
std::shared_ptr< security::integrity_policy > integrity_policy_
std::unique_ptr< log_formatter_interface > formatter_
void set_use_stderr(bool use_stderr)
Set whether to use stderr for all output.
~console_writer() override
Destructor.
void set_use_color(bool use_color)
Set whether to use color output (if supported)
common::VoidResult write(const log_entry &entry) override
Write a log entry to console.
void set_integrity_policy(std::shared_ptr< security::integrity_policy > policy)
Enable tamper-evident integrity signing for every console record.
std::string format_entry(const log_entry &entry) const
Format a log entry using the current formatter.
common::VoidResult flush() override
Flush console streams.
std::string to_string() const
Convert to std::string.
Default formatter with human-readable timestamp format.
Console writer for logging to stdout/stderr.
Structured error context for debugging log system failures.
Tamper-evident log signing policies for writers.
Data structures for representing log entries and source locations kcenon.
VoidResult ok()
std::string format_signature_suffix(const integrity_policy &policy, const std::string &record)
Format a signature line suitable for appending to a text log record.
common::VoidResult check_stream_state(const Stream &stream, const std::string &operation_name="operation")
Stream state verification helper.
common::VoidResult try_write_operation(F &&operation, logger_error_code default_error_code=logger_error_code::file_write_failed)
Error handling helper for write operations.
common::VoidResult make_logger_void_result(logger_error_code code, const std::string &message="")
Small String Optimization (SSO) for short log messages.
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
Default human-readable formatter with timestamps kcenon.