12#include <kcenon/common/interfaces/logger_interface.h>
14#include <unordered_map>
26using log_level = common::interfaces::log_level;
31using log_value = std::variant<std::string, int, double, bool>;
42 std::unordered_map<std::string, log_value>
fields;
190 std::string formatted;
206 out << formatted << std::endl;
219 std::ostringstream oss;
230 for (
const auto& [key, value] : entry.
fields) {
231 oss <<
" " << key <<
"=";
232 std::visit([&oss](
const auto& v) {
233 using T = std::decay_t<
decltype(v)>;
234 if constexpr (std::is_same_v<T, std::string>) {
236 }
else if constexpr (std::is_same_v<T, bool>) {
237 oss << (v ?
"true" :
"false");
249 case log_level::trace:
return "trace";
250 case log_level::debug:
return "debug";
251 case log_level::info:
return "info";
252 case log_level::warning:
return "warn";
253 case log_level::error:
return "error";
254 case log_level::critical:
return "fatal";
255 case log_level::off:
return "off";
256 default:
return "unknown";
261 auto time_t_val = std::chrono::system_clock::to_time_t(tp);
262 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
263 tp.time_since_epoch()) % 1000;
265 std::ostringstream oss;
266 oss << std::put_time(std::gmtime(&time_t_val),
"%Y-%m-%dT%H:%M:%S");
267 oss <<
"." << std::setfill(
'0') << std::setw(3) << ms.count() <<
"Z";
273 bool needs_quoting =
false;
274 for (
char c : value) {
275 if (c ==
' ' || c ==
'"' || c ==
'=' || c ==
'\n' || c ==
'\t') {
276 needs_quoting =
true;
281 if (!needs_quoting && !value.empty()) {
286 std::ostringstream oss;
288 for (
char c : value) {
290 case '"': oss <<
"\\\"";
break;
291 case '\\': oss <<
"\\\\";
break;
292 case '\n': oss <<
"\\n";
break;
293 case '\t': oss <<
"\\t";
break;
313 std::ostringstream
json;
320 for (
const auto& [key, value] : entry.
fields) {
323 std::visit([&
json](
const auto& v) {
324 using T = std::decay_t<
decltype(v)>;
325 if constexpr (std::is_same_v<T, std::string>) {
327 }
else if constexpr (std::is_same_v<T, bool>) {
328 json << (v ?
"true" :
"false");
329 }
else if constexpr (std::is_same_v<T, int>) {
331 }
else if constexpr (std::is_same_v<T, double>) {
332 json << std::fixed << std::setprecision(6) << v;
346 case log_level::trace:
return "TRACE";
347 case log_level::debug:
return "DEBUG";
348 case log_level::info:
return "INFO";
349 case log_level::warning:
return "WARN";
350 case log_level::error:
return "ERROR";
351 case log_level::critical:
return "FATAL";
352 case log_level::off:
return "OFF";
353 default:
return "UNKNOWN";
358 auto time_t_val = std::chrono::system_clock::to_time_t(tp);
359 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
360 tp.time_since_epoch()) % 1000;
362 std::ostringstream oss;
363 oss << std::put_time(std::gmtime(&time_t_val),
"%Y-%m-%dT%H:%M:%S");
364 oss <<
"." << std::setfill(
'0') << std::setw(3) << ms.count() <<
"Z";
369 std::ostringstream oss;
373 case '"': oss <<
"\\\"";
break;
374 case '\\': oss <<
"\\\\";
break;
375 case '\b': oss <<
"\\b";
break;
376 case '\f': oss <<
"\\f";
break;
377 case '\n': oss <<
"\\n";
break;
378 case '\r': oss <<
"\\r";
break;
379 case '\t': oss <<
"\\t";
break;
381 if (
static_cast<unsigned char>(c) < 0x20) {
382 oss <<
"\\u" << std::hex << std::setfill('0') << std::setw(4) << static_cast<int>(c);
396 if (c ==
'"' || c ==
'\\') {
structured_format format_
static std::string level_to_string(log_level level)
static std::string escape_logfmt_value(const std::string &value)
void set_output_callback(structured_output_callback callback)
Set a custom output callback.
log_builder start_log(log_level level) override
Start building a structured log entry.
structured_output_callback output_callback_
void set_output_to_stderr(bool use_stderr)
Set whether to output to stderr (default: stdout)
void set_format(structured_format format)
Set the output format.
void log_structured(const structured_log_entry &entry) override
Log a structured message.
static std::string format_timestamp_logfmt(std::chrono::system_clock::time_point tp)
static std::string format_logfmt(const structured_log_entry &entry)
Format entry in logfmt style (key=value pairs)
Builder for structured log entries.
log_builder & field(const std::string &key, double value)
log_builder(log_level level, structured_logger_interface *logger)
structured_logger_interface * logger_
log_builder & field(const std::string &key, const log_value &value)
log_builder & field(const std::string &key, bool value)
structured_log_entry entry_
log_builder & field(const std::string &key, int value)
log_builder & field(const std::string &key, const std::string &value)
log_builder & message(const std::string &msg)
Structured logger interface.
virtual void log_structured(const structured_log_entry &entry)=0
Log a structured message.
virtual class log_builder start_log(log_level level)=0
Start building a structured log entry.
virtual ~structured_logger_interface()=default
std::function< void(log_level, const std::string &)> structured_output_callback
Output callback type for structured logger.
std::variant< std::string, int, double, bool > log_value
Value type for structured logging.
structured_format
Output format for structured logs.
std::unordered_map< std::string, log_value > fields
std::chrono::system_clock::time_point timestamp