9 #include "quill/backend/StringFromTime.h" 10 #include "quill/bundled/fmt/format.h" 11 #include "quill/core/Attributes.h" 12 #include "quill/core/Common.h" 13 #include "quill/core/QuillError.h" 22 #include <string_view> 42 enum AdditionalSpecifier : uint8_t
52 explicit TimestampFormatter(std::string time_format, Timezone timestamp_timezone = Timezone::LocalTime)
53 : _time_format(std::move(time_format)), _timestamp_timezone(timestamp_timezone)
55 assert((_timestamp_timezone == Timezone::LocalTime || _timestamp_timezone == Timezone::GmtTime) &&
56 "Invalid timezone type");
59 size_t specifier_begin{std::string::npos};
63 if (
size_t const search_qms = _time_format.find(specifier_name[AdditionalSpecifier::Qms]);
64 search_qms != std::string::npos)
66 _additional_format_specifier = AdditionalSpecifier::Qms;
67 specifier_begin = search_qms;
70 if (
size_t const search_qus = _time_format.find(specifier_name[AdditionalSpecifier::Qus]);
71 search_qus != std::string::npos)
73 if (specifier_begin != std::string::npos)
75 QUILL_THROW(
QuillError{
"format specifiers %Qms, %Qus and %Qns are mutually exclusive"});
78 _additional_format_specifier = AdditionalSpecifier::Qus;
79 specifier_begin = search_qus;
82 if (
size_t const search_qns = _time_format.find(specifier_name[AdditionalSpecifier::Qns]);
83 search_qns != std::string::npos)
85 if (specifier_begin != std::string::npos)
87 QUILL_THROW(
QuillError{
"format specifiers %Qms, %Qus and %Qns are mutually exclusive"});
90 _additional_format_specifier = AdditionalSpecifier::Qns;
91 specifier_begin = search_qns;
94 if (specifier_begin == std::string::npos)
97 assert(_additional_format_specifier == AdditionalSpecifier::None);
98 _strftime_part_1.init(_time_format, _timestamp_timezone);
103 std::string
const format_part_1 = _time_format.substr(0, specifier_begin);
104 _strftime_part_1.init(format_part_1, _timestamp_timezone);
107 size_t const specifier_end = specifier_begin + specifier_length;
108 std::string
const format_part_2 =
109 _time_format.substr(specifier_end, _time_format.length() - specifier_end);
111 if (!format_part_2.empty())
113 _strftime_part_2.init(format_part_2, _timestamp_timezone);
114 _has_format_part_2 =
true;
120 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::string_view format_timestamp(std::chrono::nanoseconds time_since_epoch)
122 int64_t
const timestamp_ns = time_since_epoch.count();
125 int64_t
const timestamp_secs = timestamp_ns / 1
'000'000
'000; 127 // First always clear our cached string 128 _formatted_date.clear(); 130 // 1. we always format part 1 131 _formatted_date.append(_strftime_part_1.format_timestamp(timestamp_secs)); 133 // 2. We add any special ms/us/ns specifier if any 134 auto const extracted_ns = static_cast<uint32_t>(timestamp_ns - (timestamp_secs * 1'000
'000'000));
136 if (_additional_format_specifier == AdditionalSpecifier::Qms)
138 uint32_t
const extracted_ms = extracted_ns / 1
'000'000;
141 static constexpr std::string_view zeros{
"000"};
142 _formatted_date.append(zeros);
144 _write_fractional_seconds(extracted_ms);
146 else if (_additional_format_specifier == AdditionalSpecifier::Qus)
148 uint32_t
const extracted_us = extracted_ns / 1
'000; 150 // Add as many zeros as the extracted_fractional_seconds_length 151 static constexpr std::string_view zeros{"000000"}; 152 _formatted_date.append(zeros); 154 _write_fractional_seconds(extracted_us); 156 else if (_additional_format_specifier == AdditionalSpecifier::Qns) 158 // Add as many zeros as the extracted_fractional_seconds_length 159 static constexpr std::string_view zeros{"000000000"}; 160 _formatted_date.append(zeros); 162 _write_fractional_seconds(extracted_ns); 165 // 3. format part 2 after fractional seconds - if any 166 if (_has_format_part_2) 168 _formatted_date.append(_strftime_part_2.format_timestamp(timestamp_secs)); 171 return std::string_view{_formatted_date.data(), _formatted_date.size()}; 175 QUILL_NODISCARD std::string const& time_format() const noexcept { return _time_format; } 178 QUILL_NODISCARD Timezone timestamp_timezone() const noexcept { return _timestamp_timezone; } 182 void _write_fractional_seconds(uint32_t extracted_fractional_seconds) 184 // Format the seconds and add them 185 fmtquill::format_int const extracted_ms_string{extracted_fractional_seconds}; 187 // _formatted_date.size() - extracted_ms_string.size() is where we want to begin placing the fractional seconds 188 memcpy(&_formatted_date[_formatted_date.size() - extracted_ms_string.size()], 189 extracted_ms_string.data(), extracted_ms_string.size()); 194 static constexpr std::array<char const*, 4> specifier_name{"", "%Qms", "%Qus", "%Qns"}; 197 static constexpr size_t specifier_length = 4u; 199 std::string _time_format; 200 fmtquill::basic_memory_buffer<char, 32> _formatted_date; 203 StringFromTime _strftime_part_1; 204 StringFromTime _strftime_part_2; 207 Timezone _timestamp_timezone; 210 AdditionalSpecifier _additional_format_specifier{AdditionalSpecifier::None}; 211 bool _has_format_part_2{false}; 214 } // namespace detail
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
custom exception
Definition: QuillError.h:45