Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
kcenon::logger::template_formatter Class Reference

Customizable formatter using template strings with placeholders. More...

#include <template_formatter.h>

Inheritance diagram for kcenon::logger::template_formatter:
Inheritance graph
Collaboration diagram for kcenon::logger::template_formatter:
Collaboration graph

Classes

struct  template_segment
 Segment of parsed template. More...
 

Public Member Functions

 template_formatter (const std::string &template_pattern=DEFAULT_TEMPLATE, const format_options &opts=format_options{})
 
std::string format (const log_entry &entry) const override
 Format a log entry using the template.
 
std::string get_name () const override
 Get formatter name.
 
const std::string & get_template () const
 Get current template pattern.
 
void set_template (const std::string &template_pattern)
 Set a new template pattern.
 
- Public Member Functions inherited from kcenon::logger::log_formatter_interface
virtual ~log_formatter_interface ()=default
 
virtual void set_options (const format_options &opts)
 Set formatting options.
 
virtual format_options get_options () const
 Get current formatting options.
 

Static Public Attributes

static constexpr const char * DEFAULT_TEMPLATE
 Default template pattern.
 

Private Member Functions

void parse_template ()
 Parse template string into segments.
 
std::string resolve_placeholder (const std::string &name, int width, const log_entry &entry) const
 Resolve a placeholder to its actual value.
 

Static Private Member Functions

static std::string format_field_value (const log_value &value)
 Format a structured field value to string.
 
static size_t calculate_display_width (const std::string &str)
 Calculate display width excluding ANSI escape codes.
 

Private Attributes

std::string template_
 Original template string.
 
std::vector< template_segmentsegments_
 Parsed template segments.
 

Additional Inherited Members

- Protected Attributes inherited from kcenon::logger::log_formatter_interface
format_options options_
 

Detailed Description

Customizable formatter using template strings with placeholders.

Provides flexible log formatting by allowing users to define their own output format using a template string with placeholders. This enables adaptation to various logging requirements without creating new formatter classes.

Features:

  • User-defined template strings
  • Multiple placeholder types for all log entry fields
  • Optional color support for terminal output
  • Field width formatting (e.g., {level:8} for 8-char width)
  • Fallback values for missing fields

Thread-safety: This formatter is thread-safe once constructed.

Since
3.1.0
Examples
structured_logging_example.cpp.

Definition at line 87 of file template_formatter.h.

Constructor & Destructor Documentation

◆ template_formatter()

kcenon::logger::template_formatter::template_formatter ( const std::string & template_pattern = DEFAULT_TEMPLATE,
const format_options & opts = format_options{} )
inlineexplicit
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 110 of file template_formatter.h.

112 {}
113 ) : template_(template_pattern) {
114 options_ = opts;
116 }
void parse_template()
Parse template string into segments.
std::string template_
Original template string.

Member Function Documentation

◆ calculate_display_width()

static size_t kcenon::logger::template_formatter::calculate_display_width ( const std::string & str)
inlinestaticnodiscardprivate

Calculate display width excluding ANSI escape codes.

Parameters
strString that may contain ANSI codes
Returns
Display width in characters
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 368 of file template_formatter.h.

368 {
369 size_t width = 0;
370 bool in_escape = false;
371
372 for (size_t i = 0; i < str.length(); ++i) {
373 if (str[i] == '\033') {
374 in_escape = true;
375 } else if (in_escape) {
376 if (str[i] == 'm') {
377 in_escape = false;
378 }
379 } else {
380 ++width;
381 }
382 }
383
384 return width;
385 }

Referenced by resolve_placeholder().

Here is the caller graph for this function:

◆ format()

std::string kcenon::logger::template_formatter::format ( const log_entry & entry) const
inlinenodiscardoverridevirtual

Format a log entry using the template.

Parameters
entryThe log entry to format
Returns
Formatted string according to template

Replaces all placeholders in the template with actual values from the log entry. Missing optional fields are replaced with empty strings or default values.

Note
Thread-safe. Can be called concurrently.
Since
3.1.0

Implements kcenon::logger::log_formatter_interface.

Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 131 of file template_formatter.h.

131 {
132 std::ostringstream oss;
133
134 for (const auto& segment : segments_) {
135 if (segment.is_placeholder) {
136 oss << resolve_placeholder(segment.content, segment.width, entry);
137 } else {
138 oss << segment.content;
139 }
140 }
141
142 return oss.str();
143 }
std::string resolve_placeholder(const std::string &name, int width, const log_entry &entry) const
Resolve a placeholder to its actual value.
std::vector< template_segment > segments_
Parsed template segments.

References resolve_placeholder(), and segments_.

Referenced by template_formatter_example().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_field_value()

static std::string kcenon::logger::template_formatter::format_field_value ( const log_value & value)
inlinestaticnodiscardprivate

Format a structured field value to string.

Parameters
valueThe log_value to format
Returns
String representation
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 344 of file template_formatter.h.

344 {
345 return std::visit([](const auto& v) -> std::string {
346 using T = std::decay_t<decltype(v)>;
347 if constexpr (std::is_same_v<T, std::string>) {
348 return v;
349 } else if constexpr (std::is_same_v<T, bool>) {
350 return v ? "true" : "false";
351 } else if constexpr (std::is_same_v<T, int64_t>) {
352 return std::to_string(v);
353 } else if constexpr (std::is_same_v<T, double>) {
354 std::ostringstream oss;
355 oss << std::fixed << std::setprecision(6) << v;
356 return oss.str();
357 } else {
358 return std::to_string(v);
359 }
360 }, value);
361 }

Referenced by resolve_placeholder().

Here is the caller graph for this function:

◆ get_name()

std::string kcenon::logger::template_formatter::get_name ( ) const
inlinenodiscardoverridevirtual

Get formatter name.

Returns
"template_formatter"
Since
3.1.0

Implements kcenon::logger::log_formatter_interface.

Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 151 of file template_formatter.h.

151 {
152 return "template_formatter";
153 }

◆ get_template()

const std::string & kcenon::logger::template_formatter::get_template ( ) const
inlinenodiscard

Get current template pattern.

Returns
The template string used for formatting
Since
3.1.0
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 161 of file template_formatter.h.

161 {
162 return template_;
163 }

References template_.

◆ parse_template()

void kcenon::logger::template_formatter::parse_template ( )
inlineprivate

Parse template string into segments.

Breaks down the template into literal text segments and placeholder segments for efficient formatting.

Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 200 of file template_formatter.h.

200 {
201 segments_.clear();
202
203 size_t pos = 0;
204 size_t len = template_.length();
205
206 while (pos < len) {
207 size_t start = template_.find('{', pos);
208
209 if (start == std::string::npos) {
210 // No more placeholders, add remaining text
211 if (pos < len) {
212 segments_.emplace_back(template_.substr(pos), false);
213 }
214 break;
215 }
216
217 // Add text before placeholder
218 if (start > pos) {
219 segments_.emplace_back(template_.substr(pos, start - pos), false);
220 }
221
222 // Find closing brace
223 size_t end = template_.find('}', start);
224 if (end == std::string::npos) {
225 // Unclosed brace, treat as literal
226 segments_.emplace_back(template_.substr(start), false);
227 break;
228 }
229
230 // Extract placeholder name and optional width
231 std::string placeholder = template_.substr(start + 1, end - start - 1);
232 int width = 0;
233
234 size_t colon_pos = placeholder.find(':');
235 if (colon_pos != std::string::npos) {
236 std::string width_str = placeholder.substr(colon_pos + 1);
237 placeholder = placeholder.substr(0, colon_pos);
238 try {
239 width = std::stoi(width_str);
240 } catch (...) {
241 width = 0;
242 }
243 }
244
245 segments_.emplace_back(placeholder, true, width);
246 pos = end + 1;
247 }
248 }

References segments_, and template_.

Referenced by set_template().

Here is the caller graph for this function:

◆ resolve_placeholder()

std::string kcenon::logger::template_formatter::resolve_placeholder ( const std::string & name,
int width,
const log_entry & entry ) const
inlinenodiscardprivate

Resolve a placeholder to its actual value.

Parameters
namePlaceholder name
widthOptional field width
entryLog entry to extract value from
Returns
Resolved value string
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 257 of file template_formatter.h.

261 {
262 std::string value;
263
264 if (name == "timestamp") {
265 value = utils::time_utils::format_iso8601(entry.timestamp);
266 } else if (name == "timestamp_local") {
267 value = utils::time_utils::format_timestamp(entry.timestamp);
268 } else if (name == "level") {
269 std::string level_str = utils::string_utils::level_to_string(entry.level);
270 if (options_.use_colors) {
271 value = utils::string_utils::level_to_color(entry.level) +
272 level_str +
274 } else {
275 value = level_str;
276 }
277 } else if (name == "level_lower") {
280 );
281 } else if (name == "message") {
282 value = entry.message.to_string();
283 } else if (name == "thread_id") {
284 if (entry.thread_id) {
285 value = entry.thread_id->to_string();
286 }
287 } else if (name == "file") {
288 if (entry.location) {
289 value = entry.location->file.to_string();
290 }
291 } else if (name == "filename") {
292 if (entry.location) {
294 entry.location->file.to_string()
295 );
296 }
297 } else if (name == "line") {
298 if (entry.location && entry.location->line > 0) {
299 value = std::to_string(entry.location->line);
300 }
301 } else if (name == "function") {
302 if (entry.location) {
303 value = entry.location->function.to_string();
304 }
305 } else if (name == "category") {
306 if (entry.category) {
307 value = entry.category->to_string();
308 }
309 } else if (name == "trace_id") {
310 if (entry.otel_ctx && !entry.otel_ctx->trace_id.empty()) {
311 value = entry.otel_ctx->trace_id;
312 }
313 } else if (name == "span_id") {
314 if (entry.otel_ctx && !entry.otel_ctx->span_id.empty()) {
315 value = entry.otel_ctx->span_id;
316 }
317 } else {
318 // Check structured fields
319 if (entry.fields) {
320 auto it = entry.fields->find(name);
321 if (it != entry.fields->end()) {
322 value = format_field_value(it->second);
323 }
324 }
325 }
326
327 // Apply width formatting if specified
328 if (width > 0 && !value.empty()) {
329 // Calculate actual display width (excluding ANSI codes)
330 size_t display_len = calculate_display_width(value);
331 if (display_len < static_cast<size_t>(width)) {
332 value += std::string(width - display_len, ' ');
333 }
334 }
335
336 return value;
337 }
static std::string format_field_value(const log_value &value)
Format a structured field value to string.
static size_t calculate_display_width(const std::string &str)
Calculate display width excluding ANSI escape codes.
static std::string level_to_color(log_level level, bool use_colors=true)
Convert log level to ANSI color code.
static std::string level_to_string(log_level level)
Convert log level to human-readable string.
static const char * color_reset()
ANSI color reset sequence.
static std::string to_lower(const std::string &str)
Convert string to lowercase.
static std::string extract_filename(const std::string &file_path)
Extract filename from full file path.
static std::string format_timestamp(const std::chrono::system_clock::time_point &tp)
Format timestamp to human-readable format (YYYY-MM-DD HH:MM:SS.mmm)
Definition time_utils.h:38
static std::string format_iso8601(const std::chrono::system_clock::time_point &tp)
Format timestamp to ISO 8601 / RFC 3339 format with UTC timezone.
Definition time_utils.h:76

References calculate_display_width(), kcenon::logger::log_entry::category, kcenon::logger::utils::string_utils::color_reset(), kcenon::logger::utils::string_utils::extract_filename(), kcenon::logger::log_entry::fields, format_field_value(), kcenon::logger::utils::time_utils::format_iso8601(), kcenon::logger::utils::time_utils::format_timestamp(), kcenon::logger::log_entry::level, kcenon::logger::utils::string_utils::level_to_color(), kcenon::logger::utils::string_utils::level_to_string(), kcenon::logger::log_entry::location, kcenon::logger::log_entry::message, kcenon::logger::log_formatter_interface::options_, kcenon::logger::log_entry::otel_ctx, kcenon::logger::log_entry::thread_id, kcenon::logger::log_entry::timestamp, kcenon::logger::utils::string_utils::to_lower(), kcenon::logger::small_string< SSO_SIZE >::to_string(), and kcenon::logger::format_options::use_colors.

Referenced by format().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_template()

void kcenon::logger::template_formatter::set_template ( const std::string & template_pattern)
inline

Set a new template pattern.

Parameters
template_patternNew template string
Note
This method re-parses the template.
Since
3.1.0
Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 173 of file template_formatter.h.

173 {
174 template_ = template_pattern;
176 }

References parse_template(), and template_.

Referenced by template_formatter_example().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ DEFAULT_TEMPLATE

const char* kcenon::logger::template_formatter::DEFAULT_TEMPLATE
staticconstexpr
Initial value:
=
"[{timestamp}] [{level}] [{thread_id}] {message}"

Default template pattern.

Examples
/home/runner/work/logger_system/logger_system/include/kcenon/logger/formatters/template_formatter.h.

Definition at line 92 of file template_formatter.h.

◆ segments_

std::vector<template_segment> kcenon::logger::template_formatter::segments_
private

◆ template_

std::string kcenon::logger::template_formatter::template_
private

The documentation for this class was generated from the following file: