9 #include "quill/backend/TimestampFormatter.h" 10 #include "quill/bundled/fmt/base.h" 11 #include "quill/bundled/fmt/format.h" 12 #include "quill/core/Attributes.h" 13 #include "quill/core/Common.h" 14 #include "quill/core/MacroMetadata.h" 15 #include "quill/core/PatternFormatterOptions.h" 16 #include "quill/core/QuillError.h" 25 #include <string_view> 27 #include <unordered_map> 50 enum Attribute : uint8_t
83 : _options(
std::move(options)),
84 _timestamp_formatter(_options.timestamp_pattern, _options.timestamp_timezone)
100 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::string_view format(
101 uint64_t timestamp, std::string_view thread_id, std::string_view thread_name,
102 std::string_view process_id, std::string_view logger, std::string_view log_level_description,
103 std::string_view log_level_short_code,
MacroMetadata const& log_statement_metadata,
104 std::vector<std::pair<std::string, std::string>>
const* named_args, std::string_view log_msg,
105 std::string_view mdc)
107 if (_options.format_pattern.empty())
112 return std::string_view{};
116 _formatted_log_message_buffer.clear();
118 if (QUILL_UNLIKELY(log_msg.empty()))
121 return _format(timestamp, thread_id, thread_name, process_id, logger, log_level_description,
122 log_level_short_code, log_statement_metadata, named_args, log_msg, mdc);
125 std::string_view formatted_log_msg;
128 if (_options.add_metadata_to_multi_line_logs && (!named_args || named_args->empty()))
133 while (start < log_msg.size())
135 size_t const end = log_msg.find_first_of(
'\n', start);
137 if (end == std::string_view::npos)
141 _format(timestamp, thread_id, thread_name, process_id, logger, log_level_description,
142 log_level_short_code, log_statement_metadata, named_args,
143 std::string_view(log_msg.data() + start, log_msg.size() - start), mdc);
148 size_t line_length = end - start;
149 if (_options.pattern_suffix !=
'\n')
155 formatted_log_msg = _format(timestamp, thread_id, thread_name, process_id, logger, log_level_description,
156 log_level_short_code, log_statement_metadata, named_args,
157 std::string_view(log_msg.data() + start, line_length), mdc);
166 "log_msg should not be empty, already checked earlier in PatternFormatter::format()");
167 size_t log_message_size = log_msg.size();
169 if (_options.pattern_suffix ==
'\n' && log_msg[log_msg.size() - 1] ==
'\n')
172 log_message_size = log_msg.size() - 1;
175 formatted_log_msg = _format(timestamp, thread_id, thread_name, process_id, logger,
176 log_level_description, log_level_short_code, log_statement_metadata,
177 named_args, std::string_view{log_msg.data(), log_message_size}, mdc);
180 return formatted_log_msg;
188 QUILL_NODISCARD
static std::string_view _process_source_location_path(std::string_view source_location,
189 std::string
const& strip_prefix,
190 bool remove_relative_paths)
192 std::string_view result = source_location;
195 if (remove_relative_paths)
199 #if defined(_WIN32) && defined(_MSC_VER) && !defined(__GNUC__) 200 static constexpr std::string_view relative_path =
"..\\";
202 static constexpr std::string_view relative_path =
"../";
205 if (
size_t n = result.rfind(relative_path); n != std::string_view::npos)
207 result = result.substr(n + relative_path.size());
212 if (!strip_prefix.empty())
215 size_t prefix_pos = result.rfind(strip_prefix);
217 if (prefix_pos != std::string_view::npos)
219 size_t after_prefix_pos = prefix_pos + strip_prefix.size();
223 if (after_prefix_pos < result.length() && result[after_prefix_pos] == detail::PATH_PREFERRED_SEPARATOR)
228 return result.substr(after_prefix_pos);
241 using namespace fmtquill::literals;
242 std::tie(_fmt_format, _order_index) = _generate_fmt_format_string(
243 _is_set_in_pattern, _options.format_pattern,
"time"_a =
"",
"file_name"_a =
"",
244 "caller_function"_a =
"",
"log_level"_a =
"",
"log_level_short_code"_a =
"",
245 "line_number"_a =
"",
"logger"_a =
"",
"full_path"_a =
"",
"thread_id"_a =
"",
246 "thread_name"_a =
"",
"process_id"_a =
"",
"source_location"_a =
"",
247 "short_source_location"_a =
"",
"message"_a =
"",
"mdc"_a =
"",
"tags"_a =
"",
248 "named_args"_a =
"");
250 _set_arg<Attribute::Time>(std::string_view(
"time"));
251 _set_arg<Attribute::FileName>(std::string_view(
"file_name"));
252 _set_arg<Attribute::CallerFunction>(std::string_view(
"caller_function"));
253 _set_arg<Attribute::LogLevel>(std::string_view(
"log_level"));
254 _set_arg<Attribute::LogLevelShortCode>(std::string_view(
"log_level_short_code"));
255 _set_arg<Attribute::LineNumber>(
"line_number");
256 _set_arg<Attribute::Logger>(std::string_view(
"logger"));
257 _set_arg<Attribute::FullPath>(std::string_view(
"full_path"));
258 _set_arg<Attribute::ThreadId>(std::string_view(
"thread_id"));
259 _set_arg<Attribute::ThreadName>(std::string_view(
"thread_name"));
260 _set_arg<Attribute::ProcessId>(std::string_view(
"process_id"));
261 _set_arg<Attribute::SourceLocation>(
"source_location");
262 _set_arg<Attribute::ShortSourceLocation>(
"short_source_location");
263 _set_arg<Attribute::Message>(std::string_view(
"message"));
264 _set_arg<Attribute::Mdc>(std::string_view(
"mdc"));
265 _set_arg<Attribute::Tags>(std::string_view(
"tags"));
266 _set_arg<Attribute::NamedArgs>(std::string_view(
"named_args"));
270 template <
size_t I,
typename T>
271 void _set_arg(T
const& arg)
273 _args[_order_index[I]] = arg;
276 template <
size_t I,
typename T>
277 void _set_arg_val(T
const& arg)
280 fmtquill::detail::value<fmtquill::format_context>& value_ =
281 *(
reinterpret_cast<fmtquill::detail::value<fmtquill::format_context>*
>(
282 std::addressof(_args[_order_index[I]])));
284 value_ = fmtquill::detail::value<fmtquill::format_context>(arg);
288 PatternFormatter::Attribute
static _attribute_from_string(std::string
const& attribute_name)
290 if (attribute_name ==
"time")
292 return PatternFormatter::Attribute::Time;
294 if (attribute_name ==
"file_name")
296 return PatternFormatter::Attribute::FileName;
298 if (attribute_name ==
"caller_function")
300 return PatternFormatter::Attribute::CallerFunction;
302 if (attribute_name ==
"log_level")
304 return PatternFormatter::Attribute::LogLevel;
306 if (attribute_name ==
"log_level_short_code")
308 return PatternFormatter::Attribute::LogLevelShortCode;
310 if (attribute_name ==
"line_number")
312 return PatternFormatter::Attribute::LineNumber;
314 if (attribute_name ==
"logger")
316 return PatternFormatter::Attribute::Logger;
318 if (attribute_name ==
"full_path")
320 return PatternFormatter::Attribute::FullPath;
322 if (attribute_name ==
"thread_id")
324 return PatternFormatter::Attribute::ThreadId;
326 if (attribute_name ==
"thread_name")
328 return PatternFormatter::Attribute::ThreadName;
330 if (attribute_name ==
"process_id")
332 return PatternFormatter::Attribute::ProcessId;
334 if (attribute_name ==
"source_location")
336 return PatternFormatter::Attribute::SourceLocation;
338 if (attribute_name ==
"short_source_location")
340 return PatternFormatter::Attribute::ShortSourceLocation;
342 if (attribute_name ==
"message")
344 return PatternFormatter::Attribute::Message;
346 if (attribute_name ==
"mdc")
348 return PatternFormatter::Attribute::Mdc;
350 if (attribute_name ==
"tags")
352 return PatternFormatter::Attribute::Tags;
354 if (attribute_name ==
"named_args")
356 return PatternFormatter::Attribute::NamedArgs;
360 std::string{
"Attribute enum value does not exist for attribute with name " + attribute_name}});
364 template <
size_t,
size_t>
365 constexpr
void _store_named_args(std::array<fmtquill::detail::named_arg_info<char>, PatternFormatter::Attribute::ATTR_NR_ITEMS>&)
370 template <
size_t Idx,
size_t NamedIdx,
typename Arg,
typename... Args>
371 constexpr
void _store_named_args(
372 std::array<fmtquill::detail::named_arg_info<char>, PatternFormatter::Attribute::ATTR_NR_ITEMS>& named_args_store,
373 Arg
const& arg, Args
const&... args)
375 named_args_store[NamedIdx] = {arg.name, Idx};
376 _store_named_args<Idx + 1, NamedIdx + 1>(named_args_store, args...);
405 template <
typename... Args>
406 QUILL_NODISCARD std::pair<std::string, std::array<size_t, PatternFormatter::Attribute::ATTR_NR_ITEMS>> _generate_fmt_format_string(
407 std::bitset<PatternFormatter::Attribute::ATTR_NR_ITEMS>& is_set_in_pattern, std::string pattern,
411 static_assert(PatternFormatter::Attribute::ATTR_NR_ITEMS ==
sizeof...(Args));
415 pattern += _options.pattern_suffix;
418 std::array<size_t, PatternFormatter::Attribute::ATTR_NR_ITEMS> order_index{};
419 order_index.fill(PatternFormatter::Attribute::ATTR_NR_ITEMS - 1);
421 std::array<fmtquill::detail::named_arg_info<char>, PatternFormatter::Attribute::ATTR_NR_ITEMS> named_args{};
422 _store_named_args<0, 0>(named_args, args...);
426 size_t arg_identifier_pos = pattern.find_first_of(
'%');
427 while (arg_identifier_pos != std::string::npos)
429 if (
size_t const open_paren_pos = pattern.find_first_of(
'(', arg_identifier_pos);
430 open_paren_pos != std::string::npos && (open_paren_pos - arg_identifier_pos) == 1)
433 size_t const closed_paren_pos = pattern.find_first_of(
')', open_paren_pos);
435 if (closed_paren_pos == std::string::npos)
437 QUILL_THROW(
QuillError{
"Invalid format pattern"});
441 std::string attr = pattern.substr(arg_identifier_pos, (closed_paren_pos + 1) - arg_identifier_pos);
444 size_t const pos = attr.find(
':');
445 std::string attr_name;
447 if (pos != std::string::npos)
454 std::string custom_format_specifier = attr.substr(pos);
455 custom_format_specifier.pop_back();
460 value += custom_format_specifier;
464 pattern.replace(arg_identifier_pos, attr.length(), value);
468 attr_name = attr.substr(2, pos - 2);
473 pattern.replace(arg_identifier_pos, attr.length(),
"{}");
479 attr_name = attr.substr(2, attr.size());
485 for (
size_t i = 0; i < PatternFormatter::Attribute::ATTR_NR_ITEMS; ++i)
487 if (named_args[i].name == attr_name)
489 id = named_args[i].id;
496 QUILL_THROW(
QuillError{
"Invalid format pattern, attribute with name \"" + attr_name +
"\" is invalid"});
500 PatternFormatter::Attribute
const attr_enum_value = _attribute_from_string(attr_name);
501 if (is_set_in_pattern.test(attr_enum_value))
503 QUILL_THROW(
QuillError{
"Invalid format pattern, attribute with name \"" + attr_name +
504 "\" is used more than once"});
507 order_index[
static_cast<size_t>(id)] = arg_idx++;
508 is_set_in_pattern.set(attr_enum_value);
511 arg_identifier_pos = pattern.find_first_of(
'%');
516 arg_identifier_pos = pattern.find_first_of(
'%', arg_identifier_pos + 1);
520 return std::make_pair(pattern, order_index);
524 QUILL_ATTRIBUTE_HOT std::string_view _format(uint64_t timestamp, std::string_view thread_id,
525 std::string_view thread_name, std::string_view process_id,
526 std::string_view logger, std::string_view log_level_description,
527 std::string_view log_level_short_code,
529 std::vector<std::pair<std::string, std::string>>
const* named_args,
530 std::string_view log_msg, std::string_view mdc)
532 if (_is_set_in_pattern[Attribute::Time])
534 _set_arg_val<Attribute::Time>(_timestamp_formatter.format_timestamp(std::chrono::nanoseconds{timestamp}));
537 if (_is_set_in_pattern[Attribute::FileName])
539 _set_arg_val<Attribute::FileName>(log_statement_metadata.file_name());
542 if (_is_set_in_pattern[Attribute::CallerFunction])
544 std::string_view
const function_name = _options.process_function_name
545 ? _options.process_function_name(log_statement_metadata.caller_function())
546 : std::string_view{log_statement_metadata.caller_function()};
548 _set_arg_val<Attribute::CallerFunction>(function_name);
551 if (_is_set_in_pattern[Attribute::LogLevel])
553 _set_arg_val<Attribute::LogLevel>(log_level_description);
556 if (_is_set_in_pattern[Attribute::LogLevelShortCode])
558 _set_arg_val<Attribute::LogLevelShortCode>(log_level_short_code);
561 if (_is_set_in_pattern[Attribute::LineNumber])
563 _set_arg_val<Attribute::LineNumber>(log_statement_metadata.line());
566 if (_is_set_in_pattern[Attribute::Logger])
568 _set_arg_val<Attribute::Logger>(logger);
571 if (_is_set_in_pattern[Attribute::FullPath])
573 _set_arg_val<Attribute::FullPath>(log_statement_metadata.full_path());
576 if (_is_set_in_pattern[Attribute::ThreadId])
578 _set_arg_val<Attribute::ThreadId>(thread_id);
581 if (_is_set_in_pattern[Attribute::ThreadName])
583 _set_arg_val<Attribute::ThreadName>(thread_name);
586 if (_is_set_in_pattern[Attribute::ProcessId])
588 _set_arg_val<Attribute::ProcessId>(process_id);
591 if (_is_set_in_pattern[Attribute::SourceLocation])
593 _set_arg_val<Attribute::SourceLocation>(_process_source_location_path(
594 log_statement_metadata.source_location(), _options.source_location_path_strip_prefix,
595 _options.source_location_remove_relative_paths));
598 if (_is_set_in_pattern[Attribute::ShortSourceLocation])
600 _set_arg_val<Attribute::ShortSourceLocation>(log_statement_metadata.short_source_location());
603 if (_is_set_in_pattern[Attribute::NamedArgs])
605 _formatted_named_args_buffer.clear();
609 for (
size_t i = 0; i < named_args->size(); ++i)
611 _formatted_named_args_buffer.append((*named_args)[i].first);
612 _formatted_named_args_buffer.append(std::string_view{
": "});
613 _formatted_named_args_buffer.append((*named_args)[i].second);
615 if (i != named_args->size() - 1)
617 _formatted_named_args_buffer.append(std::string_view{
", "});
622 _set_arg_val<Attribute::NamedArgs>(
623 std::string_view{_formatted_named_args_buffer.data(), _formatted_named_args_buffer.size()});
626 if (_is_set_in_pattern[Attribute::Mdc])
628 _set_arg_val<Attribute::Mdc>(mdc);
631 if (_is_set_in_pattern[Attribute::Tags])
633 if (log_statement_metadata.tags())
635 _set_arg_val<Attribute::Tags>(std::string_view{log_statement_metadata.tags()});
639 _set_arg_val<Attribute::Tags>(std::string_view{});
643 _set_arg_val<Attribute::Message>(log_msg);
645 fmtquill::vformat_to(std::back_inserter(_formatted_log_message_buffer), _fmt_format,
646 fmtquill::basic_format_args(_args.data(),
static_cast<int>(_args.size())));
648 return std::string_view{_formatted_log_message_buffer.data(), _formatted_log_message_buffer.size()};
653 std::string _fmt_format;
656 std::array<size_t, Attribute::ATTR_NR_ITEMS> _order_index{};
657 std::array<fmtquill::basic_format_arg<fmtquill::format_context>, Attribute::ATTR_NR_ITEMS> _args{};
658 std::bitset<Attribute::ATTR_NR_ITEMS> _is_set_in_pattern;
665 fmtquill::basic_memory_buffer<char, 512> _formatted_log_message_buffer;
666 fmtquill::basic_memory_buffer<char, 512> _formatted_named_args_buffer;
Definition: UserDefinedDirectFormatFuzzer.cpp:81
custom exception
Definition: QuillError.h:47
Definition: SourceLocation.h:40