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" 21 #include <string_view> 41 enum AdditionalSpecifier : uint8_t
51 explicit TimestampFormatter(std::string time_format, Timezone timestamp_timezone = Timezone::LocalTime)
52 : _time_format(std::move(time_format)), _timestamp_timezone(timestamp_timezone)
55 _timestamp_timezone == Timezone::LocalTime || _timestamp_timezone == Timezone::GmtTime,
56 "Invalid timezone type in TimestampFormatter constructor, must be LocalTime or GmtTime");
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 QUILL_ASSERT(_additional_format_specifier == AdditionalSpecifier::None,
98 "Unexpected specifier state in TimestampFormatter constructor, should be None " 99 "when no specifier found");
100 _strftime_part_1.init(_time_format, _timestamp_timezone);
105 std::string
const format_part_1 = _time_format.substr(0, specifier_begin);
106 _strftime_part_1.init(format_part_1, _timestamp_timezone);
109 size_t const specifier_end = specifier_begin + specifier_length;
110 std::string
const format_part_2 =
111 _time_format.substr(specifier_end, _time_format.length() - specifier_end);
113 if (!format_part_2.empty())
115 _strftime_part_2.init(format_part_2, _timestamp_timezone);
116 _has_format_part_2 =
true;
122 QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::string_view format_timestamp(std::chrono::nanoseconds time_since_epoch)
124 int64_t
const timestamp_ns = time_since_epoch.count();
127 int64_t
const timestamp_secs = timestamp_ns / 1
'000'000
'000; 129 // First always clear our cached string 130 _formatted_date.clear(); 132 // 1. we always format part 1 133 _formatted_date.append(_strftime_part_1.format_timestamp(timestamp_secs)); 135 // 2. We add any special ms/us/ns specifier if any 136 auto const extracted_ns = static_cast<uint32_t>(timestamp_ns - (timestamp_secs * 1'000
'000'000));
138 if (_additional_format_specifier == AdditionalSpecifier::Qms)
140 uint32_t
const extracted_ms = extracted_ns / 1
'000'000;
143 static constexpr std::string_view zeros{
"000"};
144 _formatted_date.append(zeros);
146 _write_fractional_seconds(extracted_ms);
148 else if (_additional_format_specifier == AdditionalSpecifier::Qus)
150 uint32_t
const extracted_us = extracted_ns / 1
'000; 152 // Add as many zeros as the extracted_fractional_seconds_length 153 static constexpr std::string_view zeros{"000000"}; 154 _formatted_date.append(zeros); 156 _write_fractional_seconds(extracted_us); 158 else if (_additional_format_specifier == AdditionalSpecifier::Qns) 160 // Add as many zeros as the extracted_fractional_seconds_length 161 static constexpr std::string_view zeros{"000000000"}; 162 _formatted_date.append(zeros); 164 _write_fractional_seconds(extracted_ns); 167 // 3. format part 2 after fractional seconds - if any 168 if (_has_format_part_2) 170 _formatted_date.append(_strftime_part_2.format_timestamp(timestamp_secs)); 173 return std::string_view{_formatted_date.data(), _formatted_date.size()}; 177 QUILL_NODISCARD std::string const& time_format() const noexcept { return _time_format; } 180 QUILL_NODISCARD Timezone timestamp_timezone() const noexcept { return _timestamp_timezone; } 184 void _write_fractional_seconds(uint32_t extracted_fractional_seconds) 186 // Format the seconds and add them 187 fmtquill::format_int const extracted_ms_string{extracted_fractional_seconds}; 189 // _formatted_date.size() - extracted_ms_string.size() is where we want to begin placing the fractional seconds 190 std::memcpy(&_formatted_date[_formatted_date.size() - extracted_ms_string.size()], 191 extracted_ms_string.data(), extracted_ms_string.size()); 196 static constexpr std::array<char const*, 4> specifier_name{"", "%Qms", "%Qus", "%Qns"}; 199 static constexpr size_t specifier_length = 4u; 201 std::string _time_format; 202 fmtquill::basic_memory_buffer<char, 32> _formatted_date; 205 StringFromTime _strftime_part_1; 206 StringFromTime _strftime_part_2; 209 Timezone _timestamp_timezone; 212 AdditionalSpecifier _additional_format_specifier{AdditionalSpecifier::None}; 213 bool _has_format_part_2{false}; 216 } // namespace detail
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
custom exception
Definition: QuillError.h:45