Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
json_formatter.h
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
5#pragma once
6
11#include <sstream>
12#include <iomanip>
13#include <type_traits>
14#include <variant>
15
16// Use common_system's standard interface
17#include <kcenon/common/interfaces/logger_interface.h>
18
44namespace kcenon::logger {
45
70public:
79 explicit json_formatter(const format_options& opts = format_options{}) {
80 options_ = opts;
81 // JSON doesn't support colors
82 options_.use_colors = false;
83 }
84
101 std::string format(const log_entry& entry) const override {
102 std::ostringstream oss;
103 const char* indent = options_.pretty_print ? " " : "";
104 const char* newline = options_.pretty_print ? "\n" : "";
105
106 oss << "{" << newline;
107
108 bool first = true;
109
110 // Timestamp (ISO 8601)
112 if (!first) oss << "," << newline;
113 oss << indent << "\"timestamp\":\"" << utils::time_utils::format_iso8601(entry.timestamp) << "\"";
114 first = false;
115 }
116
117 // Level
119 if (!first) oss << "," << newline;
120 oss << indent << "\"level\":\"" << utils::string_utils::level_to_string(entry.level) << "\"";
121 first = false;
122 }
123
124 // Thread ID
125 if (options_.include_thread_id && entry.thread_id) {
126 if (!first) oss << "," << newline;
127 oss << indent << "\"thread_id\":\"" << utils::string_utils::escape_json(entry.thread_id->to_string()) << "\"";
128 first = false;
129 }
130
131 // Message (always include)
132 if (!first) oss << "," << newline;
133 oss << indent << "\"message\":\"" << utils::string_utils::escape_json(entry.message.to_string()) << "\"";
134 first = false;
135
136 // Source location
138 std::string file_path = entry.location->file.to_string();
139 if (!file_path.empty()) {
140 oss << "," << newline << indent << "\"file\":\"" << utils::string_utils::escape_json(file_path) << "\"";
141 }
142
143 if (entry.location->line > 0) {
144 oss << "," << newline << indent << "\"line\":" << entry.location->line;
145 }
146
147 std::string func = entry.location->function.to_string();
148 if (!func.empty()) {
149 oss << "," << newline << indent << "\"function\":\"" << utils::string_utils::escape_json(func) << "\"";
150 }
151 }
152
153 // Category (if present)
154 if (entry.category) {
155 std::string cat = entry.category->to_string();
156 if (!cat.empty()) {
157 oss << "," << newline << indent << "\"category\":\"" << utils::string_utils::escape_json(cat) << "\"";
158 }
159 }
160
161 // OpenTelemetry context (if present)
162 if (entry.otel_ctx && entry.otel_ctx->is_valid()) {
163 if (!entry.otel_ctx->trace_id.empty()) {
164 oss << "," << newline << indent << "\"trace_id\":\"" << utils::string_utils::escape_json(entry.otel_ctx->trace_id) << "\"";
165 }
166 if (!entry.otel_ctx->span_id.empty()) {
167 oss << "," << newline << indent << "\"span_id\":\"" << utils::string_utils::escape_json(entry.otel_ctx->span_id) << "\"";
168 }
169 if (!entry.otel_ctx->trace_flags.empty()) {
170 oss << "," << newline << indent << "\"trace_flags\":\"" << utils::string_utils::escape_json(entry.otel_ctx->trace_flags) << "\"";
171 }
172 }
173
174 // Structured fields (if present)
175 if (entry.fields && !entry.fields->empty()) {
176 for (const auto& [key, value] : *entry.fields) {
177 oss << "," << newline << indent << "\"" << utils::string_utils::escape_json(key) << "\":";
178 format_value(oss, value);
179 }
180 }
181
182 oss << newline << "}";
183
184 return oss.str();
185 }
186
193 std::string get_name() const override {
194 return "json_formatter";
195 }
196
197private:
203 static void format_value(std::ostringstream& oss, const log_value& value) {
204 std::visit([&oss](const auto& v) {
205 using T = std::decay_t<decltype(v)>;
206 if constexpr (std::is_same_v<T, std::string>) {
207 oss << "\"" << utils::string_utils::escape_json(v) << "\"";
208 } else if constexpr (std::is_same_v<T, bool>) {
209 oss << (v ? "true" : "false");
210 } else if constexpr (std::is_same_v<T, int64_t>) {
211 oss << v;
212 } else if constexpr (std::is_same_v<T, double>) {
213 oss << std::fixed << std::setprecision(6) << v;
214 } else {
215 oss << v;
216 }
217 }, value);
218 }
219
220 // Note: Formatting functions moved to utils::time_utils and utils::string_utils (Phase 3.4)
221 // This reduces code duplication and improves maintainability.
222};
223
224} // namespace kcenon::logger
JSON formatter for structured logging.
json_formatter(const format_options &opts=format_options{})
Constructor with optional format options.
static void format_value(std::ostringstream &oss, const log_value &value)
Format a log_value to JSON.
std::string format(const log_entry &entry) const override
Format a log entry to JSON string.
std::string get_name() const override
Get formatter name.
Abstract interface for log message formatters.
std::string to_string() const
Convert to std::string.
static std::string level_to_string(log_level level)
Convert log level to human-readable string.
static std::string escape_json(const std::string &str)
Escape special characters for JSON.
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
Data structures for representing log entries and source locations kcenon.
Interface for log message formatters (Strategy Pattern) kcenon.
std::variant< std::string, int64_t, double, bool > log_value
Value type for structured logging fields.
Definition log_entry.h:69
String utility functions for log formatting and conversion.
Configuration options for log formatting.
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
std::optional< log_fields > fields
Optional structured fields for key-value logging.
Definition log_entry.h:213
std::optional< small_string_64 > thread_id
Optional thread identifier.
Definition log_entry.h:190
std::optional< otlp::otel_context > otel_ctx
Optional OpenTelemetry context for trace correlation.
Definition log_entry.h:204
log_level level
Severity level of the log message.
Definition log_entry.h:162
std::optional< small_string_128 > category
Optional category for log filtering and routing.
Definition log_entry.h:197
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
Time utility functions for timestamp formatting.