11 #include "system/environment.h"
12 #include "time/timezone.h"
13 #include "utility/countof.h"
14 #include "utility/validate_aligned_storage.h"
22 class TextLayout::Impl
24 enum class PlaceholderType
61 explicit Placeholder(PlaceholderType t) : type(t) {}
62 Placeholder(PlaceholderType t,
const std::string& v) : type(t), value(v) {}
68 std::string placeholder;
69 std::string subpattern;
72 bool read_placeholder =
false;
79 AppendPattern(placeholder);
81 AppendPattern(subpattern);
84 read_placeholder =
true;
91 AppendPlaceholder(placeholder);
92 read_placeholder =
false;
100 if (read_placeholder)
108 if (read_placeholder)
109 AppendPattern(placeholder);
111 AppendPattern(subpattern);
114 AppendPattern(std::string(1,
'\0'));
119 const std::string&
pattern() const noexcept
126 thread_local
bool cache_initizlied =
false;
127 thread_local
bool cache_time_required =
false;
128 thread_local
bool cache_utc_required =
false;
129 thread_local
bool cache_local_required =
false;
130 thread_local
bool cache_timezone_required =
false;
131 thread_local
bool cache_millisecond_required =
false;
132 thread_local
bool cache_microsecond_required =
false;
133 thread_local
bool cache_nanosecond_required =
false;
134 thread_local uint64_t cache_seconds = 0;
135 thread_local
int cache_millisecond = 0;
136 thread_local
int cache_microsecond = 0;
137 thread_local
int cache_nanosecond = 0;
138 thread_local
char cache_utc_datetime_str[] =
"1970-01-01T01:01:01.000Z";
139 thread_local
char cache_utc_date_str[] =
"1970-01-01";
140 thread_local
char cache_utc_time_str[] =
"01:01:01.000Z";
141 thread_local
char cache_utc_year_str[] =
"1970";
142 thread_local
char cache_utc_month_str[] =
"01";
143 thread_local
char cache_utc_day_str[] =
"01";
144 thread_local
char cache_utc_hour_str[] =
"00";
145 thread_local
char cache_utc_minute_str[] =
"00";
146 thread_local
char cache_utc_second_str[] =
"00";
147 thread_local
char cache_utc_timezone_str[] =
"Z";
148 thread_local
char cache_local_datetime_str[] =
"1970-01-01T01:01:01.000+00:00";
149 thread_local
char cache_local_date_str[] =
"1970-01-01";
150 thread_local
char cache_local_time_str[] =
"01:01:01.000+00:00";
151 thread_local
char cache_local_year_str[] =
"1970";
152 thread_local
char cache_local_month_str[] =
"01";
153 thread_local
char cache_local_day_str[] =
"01";
154 thread_local
char cache_local_hour_str[] =
"00";
155 thread_local
char cache_local_minute_str[] =
"00";
156 thread_local
char cache_local_second_str[] =
"00";
157 thread_local
char cache_local_timezone_str[] =
"+00:00";
158 thread_local
char cache_millisecond_str[] =
"000";
159 thread_local
char cache_microsecond_str[] =
"000";
160 thread_local
char cache_nanosecond_str[] =
"000";
161 thread_local
bool cache_thread_required =
false;
162 thread_local uint64_t cache_thread = 0;
163 thread_local
char cache_thread_str[] =
"0x00000000";
164 thread_local
bool cache_level_required =
false;
166 thread_local
char cache_level_str[] =
"FATAL";
167 bool cache_update_datetime =
false;
170 if (cache_time_required || !cache_initizlied)
172 CppCommon::Timestamp timestamp(record.timestamp);
173 uint64_t seconds = timestamp.seconds();
174 int millisecond = timestamp.milliseconds() % 1000;
175 int microsecond = timestamp.microseconds() % 1000;
176 int nanosecond = timestamp.nanoseconds() % 1000;
178 if (nanosecond != cache_nanosecond)
180 cache_nanosecond = nanosecond;
183 if (cache_nanosecond_required || !cache_initizlied)
184 ConvertNumber(cache_nanosecond_str, nanosecond, 3);
187 if (microsecond != cache_microsecond)
189 cache_microsecond = microsecond;
192 if (cache_microsecond_required || !cache_initizlied)
193 ConvertNumber(cache_microsecond_str, microsecond, 3);
196 if (millisecond != cache_millisecond)
198 cache_millisecond = millisecond;
201 if (cache_millisecond_required || !cache_initizlied)
203 ConvertNumber(cache_millisecond_str, millisecond, 3);
204 cache_update_datetime =
true;
208 if (seconds != cache_seconds)
210 cache_seconds = seconds;
213 if (cache_timezone_required || !cache_initizlied)
215 CppCommon::Timezone local;
216 ConvertTimezone(cache_local_timezone_str, local.total().minutes(), 6);
217 cache_update_datetime =
true;
221 if (cache_utc_required || !cache_initizlied)
223 CppCommon::UtcTime utc(timestamp);
224 ConvertNumber(cache_utc_year_str, utc.year(), 4);
225 ConvertNumber(cache_utc_month_str, utc.month(), 2);
226 ConvertNumber(cache_utc_day_str, utc.day(), 2);
227 ConvertNumber(cache_utc_hour_str, utc.hour(), 2);
228 ConvertNumber(cache_utc_minute_str, utc.minute(), 2);
229 ConvertNumber(cache_utc_second_str, utc.second(), 2);
230 cache_update_datetime =
true;
234 if (cache_local_required || !cache_initizlied)
236 CppCommon::LocalTime local(timestamp);
237 ConvertNumber(cache_local_year_str, local.year(), 4);
238 ConvertNumber(cache_local_month_str, local.month(), 2);
239 ConvertNumber(cache_local_day_str, local.day(), 2);
240 ConvertNumber(cache_local_hour_str, local.hour(), 2);
241 ConvertNumber(cache_local_minute_str, local.minute(), 2);
242 ConvertNumber(cache_local_second_str, local.second(), 2);
243 cache_update_datetime =
true;
249 if (cache_update_datetime)
251 char* buffer = cache_utc_date_str;
252 std::memcpy(buffer, cache_utc_year_str, CppCommon::countof(cache_utc_year_str) - 1);
253 buffer += CppCommon::countof(cache_utc_year_str) - 1;
255 std::memcpy(buffer, cache_utc_month_str, CppCommon::countof(cache_utc_month_str) - 1);
256 buffer += CppCommon::countof(cache_utc_month_str) - 1;
258 std::memcpy(buffer, cache_utc_day_str, CppCommon::countof(cache_utc_day_str) - 1);
259 buffer += CppCommon::countof(cache_utc_day_str) - 1;
261 buffer = cache_utc_time_str;
262 std::memcpy(buffer, cache_utc_hour_str, CppCommon::countof(cache_utc_hour_str) - 1);
263 buffer += CppCommon::countof(cache_utc_hour_str) - 1;
265 std::memcpy(buffer, cache_utc_minute_str, CppCommon::countof(cache_utc_minute_str) - 1);
266 buffer += CppCommon::countof(cache_utc_minute_str) - 1;
268 std::memcpy(buffer, cache_utc_second_str, CppCommon::countof(cache_utc_second_str) - 1);
269 buffer += CppCommon::countof(cache_utc_second_str) - 1;
271 std::memcpy(buffer, cache_millisecond_str, CppCommon::countof(cache_millisecond_str) - 1);
272 buffer += CppCommon::countof(cache_millisecond_str) - 1;
273 std::memcpy(buffer, cache_utc_timezone_str, CppCommon::countof(cache_utc_timezone_str) - 1);
274 buffer += CppCommon::countof(cache_utc_timezone_str) - 1;
276 buffer = cache_utc_datetime_str;
277 std::memcpy(buffer, cache_utc_date_str, CppCommon::countof(cache_utc_date_str) - 1);
278 buffer += CppCommon::countof(cache_utc_date_str) - 1;
280 std::memcpy(buffer, cache_utc_time_str, CppCommon::countof(cache_utc_time_str) - 1);
281 buffer += CppCommon::countof(cache_utc_time_str) - 1;
283 buffer = cache_local_date_str;
284 std::memcpy(buffer, cache_local_year_str, CppCommon::countof(cache_local_year_str) - 1);
285 buffer += CppCommon::countof(cache_local_year_str) - 1;
287 std::memcpy(buffer, cache_local_month_str, CppCommon::countof(cache_local_month_str) - 1);
288 buffer += CppCommon::countof(cache_local_month_str) - 1;
290 std::memcpy(buffer, cache_local_day_str, CppCommon::countof(cache_local_day_str) - 1);
291 buffer += CppCommon::countof(cache_local_day_str) - 1;
293 buffer = cache_local_time_str;
294 std::memcpy(buffer, cache_local_hour_str, CppCommon::countof(cache_local_hour_str) - 1);
295 buffer += CppCommon::countof(cache_local_hour_str) - 1;
297 std::memcpy(buffer, cache_local_minute_str, CppCommon::countof(cache_local_minute_str) - 1);
298 buffer += CppCommon::countof(cache_local_minute_str) - 1;
300 std::memcpy(buffer, cache_local_second_str, CppCommon::countof(cache_local_second_str) - 1);
301 buffer += CppCommon::countof(cache_local_second_str) - 1;
303 std::memcpy(buffer, cache_millisecond_str, CppCommon::countof(cache_millisecond_str) - 1);
304 buffer += CppCommon::countof(cache_millisecond_str) - 1;
305 std::memcpy(buffer, cache_local_timezone_str, CppCommon::countof(cache_local_timezone_str) - 1);
306 buffer += CppCommon::countof(cache_local_timezone_str) - 1;
308 buffer = cache_local_datetime_str;
309 std::memcpy(buffer, cache_local_date_str, CppCommon::countof(cache_local_date_str) - 1);
310 buffer += CppCommon::countof(cache_local_date_str) - 1;
312 std::memcpy(buffer, cache_local_time_str, CppCommon::countof(cache_local_time_str) - 1);
313 buffer += CppCommon::countof(cache_local_time_str) - 1;
315 cache_update_datetime =
false;
319 if (cache_thread_required || !cache_initizlied)
321 if (record.thread != cache_thread)
323 cache_thread = record.thread;
324 ConvertThread(cache_thread_str, cache_thread, CppCommon::countof(cache_thread_str) - 1);
329 if (cache_level_required || !cache_initizlied)
331 if (record.level != cache_level)
333 cache_level = record.level;
334 ConvertLevel(cache_level_str, cache_level, CppCommon::countof(cache_level_str) - 1);
338 cache_initizlied =
true;
344 if (record.IsFormatStored())
345 record.message = record.RestoreFormat();
348 for (
const auto& placeholder : _placeholders)
350 switch (placeholder.type)
352 case PlaceholderType::String:
355 record.raw.insert(record.raw.end(), placeholder.value.begin(), placeholder.value.end());
358 case PlaceholderType::UtcDateTime:
361 record.raw.insert(record.raw.end(), std::begin(cache_utc_datetime_str), std::end(cache_utc_datetime_str) - 1);
363 cache_time_required =
true;
364 cache_utc_required =
true;
365 cache_millisecond_required =
true;
368 case PlaceholderType::UtcDate:
371 record.raw.insert(record.raw.end(), std::begin(cache_utc_date_str), std::end(cache_utc_date_str) - 1);
373 cache_time_required =
true;
374 cache_utc_required =
true;
377 case PlaceholderType::UtcTime:
380 record.raw.insert(record.raw.end(), std::begin(cache_utc_time_str), std::end(cache_utc_time_str) - 1);
382 cache_time_required =
true;
383 cache_utc_required =
true;
384 cache_millisecond_required =
true;
387 case PlaceholderType::UtcYear:
390 record.raw.insert(record.raw.end(), std::begin(cache_utc_year_str), std::end(cache_utc_year_str) - 1);
392 cache_time_required =
true;
393 cache_utc_required =
true;
396 case PlaceholderType::UtcMonth:
399 record.raw.insert(record.raw.end(), std::begin(cache_utc_month_str), std::end(cache_utc_month_str) - 1);
401 cache_time_required =
true;
402 cache_utc_required =
true;
405 case PlaceholderType::UtcDay:
408 record.raw.insert(record.raw.end(), std::begin(cache_utc_day_str), std::end(cache_utc_day_str) - 1);
410 cache_time_required =
true;
411 cache_utc_required =
true;
414 case PlaceholderType::UtcHour:
417 record.raw.insert(record.raw.end(), std::begin(cache_utc_hour_str), std::end(cache_utc_hour_str) - 1);
419 cache_time_required =
true;
420 cache_utc_required =
true;
423 case PlaceholderType::UtcMinute:
426 record.raw.insert(record.raw.end(), std::begin(cache_utc_minute_str), std::end(cache_utc_minute_str) - 1);
428 cache_time_required =
true;
429 cache_utc_required =
true;
432 case PlaceholderType::UtcSecond:
435 record.raw.insert(record.raw.end(), std::begin(cache_utc_second_str), std::end(cache_utc_second_str) - 1);
437 cache_time_required =
true;
438 cache_utc_required =
true;
441 case PlaceholderType::UtcTimezone:
444 record.raw.insert(record.raw.end(), std::begin(cache_utc_timezone_str), std::end(cache_utc_timezone_str) - 1);
447 case PlaceholderType::LocalDateTime:
450 record.raw.insert(record.raw.end(), std::begin(cache_local_datetime_str), std::end(cache_local_datetime_str) - 1);
452 cache_time_required =
true;
453 cache_local_required =
true;
454 cache_timezone_required =
true;
455 cache_millisecond_required =
true;
458 case PlaceholderType::LocalDate:
461 record.raw.insert(record.raw.end(), std::begin(cache_local_date_str), std::end(cache_local_date_str) - 1);
463 cache_time_required =
true;
464 cache_local_required =
true;
467 case PlaceholderType::LocalTime:
470 record.raw.insert(record.raw.end(), std::begin(cache_local_time_str), std::end(cache_local_time_str) - 1);
472 cache_time_required =
true;
473 cache_local_required =
true;
474 cache_timezone_required =
true;
475 cache_millisecond_required =
true;
478 case PlaceholderType::LocalYear:
481 record.raw.insert(record.raw.end(), std::begin(cache_local_year_str), std::end(cache_local_year_str) - 1);
483 cache_time_required =
true;
484 cache_local_required =
true;
487 case PlaceholderType::LocalMonth:
490 record.raw.insert(record.raw.end(), std::begin(cache_local_month_str), std::end(cache_local_month_str) - 1);
492 cache_time_required =
true;
493 cache_local_required =
true;
496 case PlaceholderType::LocalDay:
499 record.raw.insert(record.raw.end(), std::begin(cache_local_day_str), std::end(cache_local_day_str) - 1);
501 cache_time_required =
true;
502 cache_local_required =
true;
505 case PlaceholderType::LocalHour:
508 record.raw.insert(record.raw.end(), std::begin(cache_local_hour_str), std::end(cache_local_hour_str) - 1);
510 cache_time_required =
true;
511 cache_local_required =
true;
514 case PlaceholderType::LocalMinute:
517 record.raw.insert(record.raw.end(), std::begin(cache_local_minute_str), std::end(cache_local_minute_str) - 1);
519 cache_time_required =
true;
520 cache_local_required =
true;
523 case PlaceholderType::LocalSecond:
526 record.raw.insert(record.raw.end(), std::begin(cache_local_second_str), std::end(cache_local_second_str) - 1);
528 cache_time_required =
true;
529 cache_local_required =
true;
532 case PlaceholderType::LocalTimezone:
535 record.raw.insert(record.raw.end(), std::begin(cache_local_timezone_str), std::end(cache_local_timezone_str) - 1);
537 cache_time_required =
true;
538 cache_timezone_required =
true;
541 case PlaceholderType::Millisecond:
544 record.raw.insert(record.raw.end(), std::begin(cache_millisecond_str), std::end(cache_millisecond_str) - 1);
546 cache_time_required =
true;
547 cache_millisecond_required =
true;
550 case PlaceholderType::Microsecond:
553 record.raw.insert(record.raw.end(), std::begin(cache_microsecond_str), std::end(cache_microsecond_str) - 1);
555 cache_time_required =
true;
556 cache_microsecond_required =
true;
559 case PlaceholderType::Nanosecond:
562 record.raw.insert(record.raw.end(), std::begin(cache_nanosecond_str), std::end(cache_nanosecond_str) - 1);
564 cache_time_required =
true;
565 cache_nanosecond_required =
true;
568 case PlaceholderType::Thread:
571 record.raw.insert(record.raw.end(), std::begin(cache_thread_str), std::end(cache_thread_str) - 1);
573 cache_thread_required =
true;
579 record.raw.insert(record.raw.end(), std::begin(cache_level_str), std::end(cache_level_str) - 1);
581 cache_level_required =
true;
584 case PlaceholderType::Logger:
587 record.raw.insert(record.raw.end(), record.logger.begin(), record.logger.end());
590 case PlaceholderType::Message:
593 record.raw.insert(record.raw.end(), record.message.begin(), record.message.end());
601 std::string _pattern;
602 std::vector<Placeholder> _placeholders;
604 void AppendPattern(
const std::string&
pattern)
611 if (_placeholders.empty() || (_placeholders[_placeholders.size() - 1].type != PlaceholderType::String))
612 _placeholders.emplace_back(PlaceholderType::String,
pattern);
614 _placeholders[_placeholders.size() - 1].value +=
pattern;
617 void AppendPlaceholder(
const std::string& placeholder)
620 if (placeholder.empty())
623 if (placeholder ==
"UtcDateTime")
624 _placeholders.emplace_back(PlaceholderType::UtcDateTime);
625 else if (placeholder ==
"UtcDate")
626 _placeholders.emplace_back(PlaceholderType::UtcDate);
627 else if (placeholder ==
"UtcTime")
628 _placeholders.emplace_back(PlaceholderType::UtcTime);
629 else if (placeholder ==
"UtcYear")
630 _placeholders.emplace_back(PlaceholderType::UtcYear);
631 else if (placeholder ==
"UtcMonth")
632 _placeholders.emplace_back(PlaceholderType::UtcMonth);
633 else if (placeholder ==
"UtcDay")
634 _placeholders.emplace_back(PlaceholderType::UtcDay);
635 else if (placeholder ==
"UtcHour")
636 _placeholders.emplace_back(PlaceholderType::UtcHour);
637 else if (placeholder ==
"UtcMinute")
638 _placeholders.emplace_back(PlaceholderType::UtcMinute);
639 else if (placeholder ==
"UtcSecond")
640 _placeholders.emplace_back(PlaceholderType::UtcSecond);
641 else if (placeholder ==
"UtcTimezone")
642 _placeholders.emplace_back(PlaceholderType::UtcTimezone);
643 else if (placeholder ==
"LocalDateTime")
644 _placeholders.emplace_back(PlaceholderType::LocalDateTime);
645 else if (placeholder ==
"LocalDate")
646 _placeholders.emplace_back(PlaceholderType::LocalDate);
647 else if (placeholder ==
"LocalTime")
648 _placeholders.emplace_back(PlaceholderType::LocalTime);
649 else if (placeholder ==
"LocalYear")
650 _placeholders.emplace_back(PlaceholderType::LocalYear);
651 else if (placeholder ==
"LocalMonth")
652 _placeholders.emplace_back(PlaceholderType::LocalMonth);
653 else if (placeholder ==
"LocalDay")
654 _placeholders.emplace_back(PlaceholderType::LocalDay);
655 else if (placeholder ==
"LocalHour")
656 _placeholders.emplace_back(PlaceholderType::LocalHour);
657 else if (placeholder ==
"LocalMinute")
658 _placeholders.emplace_back(PlaceholderType::LocalMinute);
659 else if (placeholder ==
"LocalSecond")
660 _placeholders.emplace_back(PlaceholderType::LocalSecond);
661 else if (placeholder ==
"LocalTimezone")
662 _placeholders.emplace_back(PlaceholderType::LocalTimezone);
663 else if (placeholder ==
"Millisecond")
664 _placeholders.emplace_back(PlaceholderType::Millisecond);
665 else if (placeholder ==
"Microsecond")
666 _placeholders.emplace_back(PlaceholderType::Microsecond);
667 else if (placeholder ==
"Nanosecond")
668 _placeholders.emplace_back(PlaceholderType::Nanosecond);
669 else if (placeholder ==
"Thread")
670 _placeholders.emplace_back(PlaceholderType::Thread);
671 else if (placeholder ==
"Level")
673 else if (placeholder ==
"Logger")
674 _placeholders.emplace_back(PlaceholderType::Logger);
675 else if (placeholder ==
"Message")
676 _placeholders.emplace_back(PlaceholderType::Message);
677 else if (placeholder ==
"EndLine")
678 AppendPattern(CppCommon::Environment::EndLine());
680 AppendPattern(
"{" + placeholder +
"}");
683 static void ConvertNumber(
char* output,
int number,
size_t size)
686 std::memset(output,
'0', size);
689 size_t index = size - 1;
692 while ((number >= 10) && (index != 0))
696 output[index--] =
'0' + (char)b;
701 output[index] =
'0' + (char)number;
704 static void ConvertThread(
char* output, uint64_t thread,
size_t size)
706 const char* digits =
"0123456789ABCDEF";
709 std::memset(output,
'0', size);
712 size_t index = size - 1;
717 output[index--] = digits[thread & 0x0F];
718 }
while (((thread >>= 4) != 0) && (index != 0));
725 static void ConvertTimezone(
char* output, int64_t offset,
size_t size)
728 std::memset(output,
'0', size);
731 size_t index = size - 1;
734 int64_t minutes = offset % 60;
737 output[index--] =
'0' + (char)minutes;
742 output[index--] =
'0' + (char)(minutes % 10);
744 output[index--] =
'0' + (char)minutes;
748 output[index--] =
':';
751 int64_t hours = offset / 60;
754 output[index] =
'0' + (char)hours;
758 output[index--] =
'0' + (char)(hours % 10);
760 output[index] =
'0' + (char)hours;
764 output[0] = (offset < 0) ?
'-' :
'+';
767 static void ConvertLevel(
char* output,
Level level,
size_t size)
770 std::memset(output,
' ', size);
775 std::memcpy(output,
"NONE", CppCommon::countof(
"NONE") - 1);
778 std::memcpy(output,
"FATAL", CppCommon::countof(
"FATAL") - 1);
781 std::memcpy(output,
"ERROR", CppCommon::countof(
"ERROR") - 1);
784 std::memcpy(output,
"WARN", CppCommon::countof(
"WARN") - 1);
787 std::memcpy(output,
"INFO", CppCommon::countof(
"INFO") - 1);
790 std::memcpy(output,
"DEBUG", CppCommon::countof(
"DEBUG") - 1);
793 std::memcpy(output,
"ALL", CppCommon::countof(
"ALL") - 1);
796 std::memcpy(output,
"<\?\?\?>", CppCommon::countof(
"<\?\?\?>") - 1);
807 [[maybe_unused]] CppCommon::ValidateAlignedStorage<
sizeof(Impl),
alignof(Impl), StorageSize, StorageAlign> _;
808 static_assert((StorageSize >=
sizeof(Impl)),
"TextLayout::StorageSize must be increased!");
809 static_assert(((StorageAlign %
alignof(Impl)) == 0),
"TextLayout::StorageAlign must be adjusted!");
812 new(&_storage)Impl(layout);
818 reinterpret_cast<Impl*
>(&_storage)->~Impl();
void LayoutRecord(Record &record) override
Layout the given logging record into a raw buffer.
const std::string & pattern() const noexcept
Get the text layout pattern.
TextLayout(const std::string &pattern="{UtcDateTime} [{Thread}] {Level} {Logger} - {Message}{EndLine}")
Initialize text logging layout with a given pattern.
C++ Logging project definitions.