CppLogging 1.0.5.0
C++ Logging Library
Loading...
Searching...
No Matches
text_layout.cpp
Go to the documentation of this file.
1
10
11#include "system/environment.h"
12#include "time/timezone.h"
13#include "utility/countof.h"
14#include "utility/validate_aligned_storage.h"
15
16#include <vector>
17
18namespace CppLogging {
19
21
22class TextLayout::Impl
23{
24 enum class PlaceholderType
25 {
26 String,
27 UtcDateTime,
28 UtcDate,
29 UtcTime,
30 UtcYear,
31 UtcMonth,
32 UtcDay,
33 UtcHour,
34 UtcMinute,
35 UtcSecond,
36 UtcTimezone,
37 LocalDateTime,
38 LocalDate,
39 LocalTime,
40 LocalYear,
41 LocalMonth,
42 LocalDay,
43 LocalHour,
44 LocalMinute,
45 LocalSecond,
46 LocalTimezone,
47 Millisecond,
48 Microsecond,
49 Nanosecond,
50 Thread,
51 Level,
52 Logger,
53 Message
54 };
55
56 struct Placeholder
57 {
58 PlaceholderType type;
59 std::string value;
60
61 explicit Placeholder(PlaceholderType t) : type(t) {}
62 Placeholder(PlaceholderType t, const std::string& v) : type(t), value(v) {}
63 };
64
65public:
66 Impl(const std::string& pattern) : _pattern(pattern)
67 {
68 std::string placeholder;
69 std::string subpattern;
70
71 // Tokenize layout pattern
72 bool read_placeholder = false;
73 for (char ch : pattern)
74 {
75 // Start reading placeholder or pattern
76 if (ch == '{')
77 {
78 if (read_placeholder)
79 AppendPattern(placeholder);
80 else
81 AppendPattern(subpattern);
82 placeholder.clear();
83 subpattern.clear();
84 read_placeholder = true;
85 }
86 // Stop reading placeholder or pattern
87 else if (ch == '}')
88 {
89 if (read_placeholder)
90 {
91 AppendPlaceholder(placeholder);
92 read_placeholder = false;
93 }
94 else
95 subpattern += ch;
96 }
97 // Continue reading placeholder or pattern
98 else
99 {
100 if (read_placeholder)
101 placeholder += ch;
102 else
103 subpattern += ch;
104 }
105 }
106
107 // Addend last value of placeholder or pattern
108 if (read_placeholder)
109 AppendPattern(placeholder);
110 else
111 AppendPattern(subpattern);
112
113 // Addend end of string character
114 AppendPattern(std::string(1, '\0'));
115 }
116
117 ~Impl() = default;
118
119 const std::string& pattern() const noexcept
120 {
121 return _pattern;
122 }
123
124 void LayoutRecord(Record& record)
125 {
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;
165 thread_local Level cache_level = Level::FATAL;
166 thread_local char cache_level_str[] = "FATAL";
167 bool cache_update_datetime = false;
168
169 // Update time cache
170 if (cache_time_required || !cache_initizlied)
171 {
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;
177
178 if (nanosecond != cache_nanosecond)
179 {
180 cache_nanosecond = nanosecond;
181
182 // Update nanosecond cache values
183 if (cache_nanosecond_required || !cache_initizlied)
184 ConvertNumber(cache_nanosecond_str, nanosecond, 3);
185 }
186
187 if (microsecond != cache_microsecond)
188 {
189 cache_microsecond = microsecond;
190
191 // Update microsecond cache values
192 if (cache_microsecond_required || !cache_initizlied)
193 ConvertNumber(cache_microsecond_str, microsecond, 3);
194 }
195
196 if (millisecond != cache_millisecond)
197 {
198 cache_millisecond = millisecond;
199
200 // Update millisecond cache values
201 if (cache_millisecond_required || !cache_initizlied)
202 {
203 ConvertNumber(cache_millisecond_str, millisecond, 3);
204 cache_update_datetime = true;
205 }
206 }
207
208 if (seconds != cache_seconds)
209 {
210 cache_seconds = seconds;
211
212 // Update timezone cache values
213 if (cache_timezone_required || !cache_initizlied)
214 {
215 CppCommon::Timezone local;
216 ConvertTimezone(cache_local_timezone_str, local.total().minutes(), 6);
217 cache_update_datetime = true;
218 }
219
220 // Update UTC time cache values
221 if (cache_utc_required || !cache_initizlied)
222 {
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;
231 }
232
233 // Update local time cache values
234 if (cache_local_required || !cache_initizlied)
235 {
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;
244 }
245 }
246 }
247
248 // Update date & time cache
249 if (cache_update_datetime)
250 {
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;
254 *buffer++ = '-';
255 std::memcpy(buffer, cache_utc_month_str, CppCommon::countof(cache_utc_month_str) - 1);
256 buffer += CppCommon::countof(cache_utc_month_str) - 1;
257 *buffer++ = '-';
258 std::memcpy(buffer, cache_utc_day_str, CppCommon::countof(cache_utc_day_str) - 1);
259 buffer += CppCommon::countof(cache_utc_day_str) - 1;
260
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;
264 *buffer++ = ':';
265 std::memcpy(buffer, cache_utc_minute_str, CppCommon::countof(cache_utc_minute_str) - 1);
266 buffer += CppCommon::countof(cache_utc_minute_str) - 1;
267 *buffer++ = ':';
268 std::memcpy(buffer, cache_utc_second_str, CppCommon::countof(cache_utc_second_str) - 1);
269 buffer += CppCommon::countof(cache_utc_second_str) - 1;
270 *buffer++ = '.';
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;
275
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;
279 *buffer++ = 'T';
280 std::memcpy(buffer, cache_utc_time_str, CppCommon::countof(cache_utc_time_str) - 1);
281 buffer += CppCommon::countof(cache_utc_time_str) - 1;
282
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;
286 *buffer++ = '-';
287 std::memcpy(buffer, cache_local_month_str, CppCommon::countof(cache_local_month_str) - 1);
288 buffer += CppCommon::countof(cache_local_month_str) - 1;
289 *buffer++ = '-';
290 std::memcpy(buffer, cache_local_day_str, CppCommon::countof(cache_local_day_str) - 1);
291 buffer += CppCommon::countof(cache_local_day_str) - 1;
292
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;
296 *buffer++ = ':';
297 std::memcpy(buffer, cache_local_minute_str, CppCommon::countof(cache_local_minute_str) - 1);
298 buffer += CppCommon::countof(cache_local_minute_str) - 1;
299 *buffer++ = ':';
300 std::memcpy(buffer, cache_local_second_str, CppCommon::countof(cache_local_second_str) - 1);
301 buffer += CppCommon::countof(cache_local_second_str) - 1;
302 *buffer++ = '.';
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;
307
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;
311 *buffer++ = 'T';
312 std::memcpy(buffer, cache_local_time_str, CppCommon::countof(cache_local_time_str) - 1);
313 buffer += CppCommon::countof(cache_local_time_str) - 1;
314
315 cache_update_datetime = false;
316 }
317
318 // Update thread cache
319 if (cache_thread_required || !cache_initizlied)
320 {
321 if (record.thread != cache_thread)
322 {
323 cache_thread = record.thread;
324 ConvertThread(cache_thread_str, cache_thread, CppCommon::countof(cache_thread_str) - 1);
325 }
326 }
327
328 // Update level cache
329 if (cache_level_required || !cache_initizlied)
330 {
331 if (record.level != cache_level)
332 {
333 cache_level = record.level;
334 ConvertLevel(cache_level_str, cache_level, CppCommon::countof(cache_level_str) - 1);
335 }
336 }
337
338 cache_initizlied = true;
339
340 // Clear raw buffer of the logging record
341 record.raw.clear();
342
343 // Restore format message
344 if (record.IsFormatStored())
345 record.message = record.RestoreFormat();
346
347 // Iterate through all placeholders
348 for (const auto& placeholder : _placeholders)
349 {
350 switch (placeholder.type)
351 {
352 case PlaceholderType::String:
353 {
354 // Output pattern string
355 record.raw.insert(record.raw.end(), placeholder.value.begin(), placeholder.value.end());
356 break;
357 }
358 case PlaceholderType::UtcDateTime:
359 {
360 // Output UTC date & time string
361 record.raw.insert(record.raw.end(), std::begin(cache_utc_datetime_str), std::end(cache_utc_datetime_str) - 1);
362 // Set the corresponding cache required flag
363 cache_time_required = true;
364 cache_utc_required = true;
365 cache_millisecond_required = true;
366 break;
367 }
368 case PlaceholderType::UtcDate:
369 {
370 // Output UTC date string
371 record.raw.insert(record.raw.end(), std::begin(cache_utc_date_str), std::end(cache_utc_date_str) - 1);
372 // Set the corresponding cache required flag
373 cache_time_required = true;
374 cache_utc_required = true;
375 break;
376 }
377 case PlaceholderType::UtcTime:
378 {
379 // Output UTC time string
380 record.raw.insert(record.raw.end(), std::begin(cache_utc_time_str), std::end(cache_utc_time_str) - 1);
381 // Set the corresponding cache required flag
382 cache_time_required = true;
383 cache_utc_required = true;
384 cache_millisecond_required = true;
385 break;
386 }
387 case PlaceholderType::UtcYear:
388 {
389 // Output UTC year string
390 record.raw.insert(record.raw.end(), std::begin(cache_utc_year_str), std::end(cache_utc_year_str) - 1);
391 // Set the corresponding cache required flag
392 cache_time_required = true;
393 cache_utc_required = true;
394 break;
395 }
396 case PlaceholderType::UtcMonth:
397 {
398 // Output UTC month string
399 record.raw.insert(record.raw.end(), std::begin(cache_utc_month_str), std::end(cache_utc_month_str) - 1);
400 // Set the corresponding cache required flag
401 cache_time_required = true;
402 cache_utc_required = true;
403 break;
404 }
405 case PlaceholderType::UtcDay:
406 {
407 // Output UTC day string
408 record.raw.insert(record.raw.end(), std::begin(cache_utc_day_str), std::end(cache_utc_day_str) - 1);
409 // Set the corresponding cache required flag
410 cache_time_required = true;
411 cache_utc_required = true;
412 break;
413 }
414 case PlaceholderType::UtcHour:
415 {
416 // Output UTC hour string
417 record.raw.insert(record.raw.end(), std::begin(cache_utc_hour_str), std::end(cache_utc_hour_str) - 1);
418 // Set the corresponding cache required flag
419 cache_time_required = true;
420 cache_utc_required = true;
421 break;
422 }
423 case PlaceholderType::UtcMinute:
424 {
425 // Output UTC minute string
426 record.raw.insert(record.raw.end(), std::begin(cache_utc_minute_str), std::end(cache_utc_minute_str) - 1);
427 // Set the corresponding cache required flag
428 cache_time_required = true;
429 cache_utc_required = true;
430 break;
431 }
432 case PlaceholderType::UtcSecond:
433 {
434 // Output UTC second string
435 record.raw.insert(record.raw.end(), std::begin(cache_utc_second_str), std::end(cache_utc_second_str) - 1);
436 // Set the corresponding cache required flag
437 cache_time_required = true;
438 cache_utc_required = true;
439 break;
440 }
441 case PlaceholderType::UtcTimezone:
442 {
443 // Output UTC timezone string
444 record.raw.insert(record.raw.end(), std::begin(cache_utc_timezone_str), std::end(cache_utc_timezone_str) - 1);
445 break;
446 }
447 case PlaceholderType::LocalDateTime:
448 {
449 // Output local date & time string
450 record.raw.insert(record.raw.end(), std::begin(cache_local_datetime_str), std::end(cache_local_datetime_str) - 1);
451 // Set the corresponding cache required flag
452 cache_time_required = true;
453 cache_local_required = true;
454 cache_timezone_required = true;
455 cache_millisecond_required = true;
456 break;
457 }
458 case PlaceholderType::LocalDate:
459 {
460 // Output local date string
461 record.raw.insert(record.raw.end(), std::begin(cache_local_date_str), std::end(cache_local_date_str) - 1);
462 // Set the corresponding cache required flag
463 cache_time_required = true;
464 cache_local_required = true;
465 break;
466 }
467 case PlaceholderType::LocalTime:
468 {
469 // Output local time string
470 record.raw.insert(record.raw.end(), std::begin(cache_local_time_str), std::end(cache_local_time_str) - 1);
471 // Set the corresponding cache required flag
472 cache_time_required = true;
473 cache_local_required = true;
474 cache_timezone_required = true;
475 cache_millisecond_required = true;
476 break;
477 }
478 case PlaceholderType::LocalYear:
479 {
480 // Output local year string
481 record.raw.insert(record.raw.end(), std::begin(cache_local_year_str), std::end(cache_local_year_str) - 1);
482 // Set the corresponding cache required flag
483 cache_time_required = true;
484 cache_local_required = true;
485 break;
486 }
487 case PlaceholderType::LocalMonth:
488 {
489 // Output local month string
490 record.raw.insert(record.raw.end(), std::begin(cache_local_month_str), std::end(cache_local_month_str) - 1);
491 // Set the corresponding cache required flag
492 cache_time_required = true;
493 cache_local_required = true;
494 break;
495 }
496 case PlaceholderType::LocalDay:
497 {
498 // Output local day string
499 record.raw.insert(record.raw.end(), std::begin(cache_local_day_str), std::end(cache_local_day_str) - 1);
500 // Set the corresponding cache required flag
501 cache_time_required = true;
502 cache_local_required = true;
503 break;
504 }
505 case PlaceholderType::LocalHour:
506 {
507 // Output local hour string
508 record.raw.insert(record.raw.end(), std::begin(cache_local_hour_str), std::end(cache_local_hour_str) - 1);
509 // Set the corresponding cache required flag
510 cache_time_required = true;
511 cache_local_required = true;
512 break;
513 }
514 case PlaceholderType::LocalMinute:
515 {
516 // Output local minute string
517 record.raw.insert(record.raw.end(), std::begin(cache_local_minute_str), std::end(cache_local_minute_str) - 1);
518 // Set the corresponding cache required flag
519 cache_time_required = true;
520 cache_local_required = true;
521 break;
522 }
523 case PlaceholderType::LocalSecond:
524 {
525 // Output local second string
526 record.raw.insert(record.raw.end(), std::begin(cache_local_second_str), std::end(cache_local_second_str) - 1);
527 // Set the corresponding cache required flag
528 cache_time_required = true;
529 cache_local_required = true;
530 break;
531 }
532 case PlaceholderType::LocalTimezone:
533 {
534 // Output local timezone string
535 record.raw.insert(record.raw.end(), std::begin(cache_local_timezone_str), std::end(cache_local_timezone_str) - 1);
536 // Set the corresponding cache required flag
537 cache_time_required = true;
538 cache_timezone_required = true;
539 break;
540 }
541 case PlaceholderType::Millisecond:
542 {
543 // Output millisecond string
544 record.raw.insert(record.raw.end(), std::begin(cache_millisecond_str), std::end(cache_millisecond_str) - 1);
545 // Set the corresponding cache required flag
546 cache_time_required = true;
547 cache_millisecond_required = true;
548 break;
549 }
550 case PlaceholderType::Microsecond:
551 {
552 // Output microsecond string
553 record.raw.insert(record.raw.end(), std::begin(cache_microsecond_str), std::end(cache_microsecond_str) - 1);
554 // Set the corresponding cache required flag
555 cache_time_required = true;
556 cache_microsecond_required = true;
557 break;
558 }
559 case PlaceholderType::Nanosecond:
560 {
561 // Output nanosecond string
562 record.raw.insert(record.raw.end(), std::begin(cache_nanosecond_str), std::end(cache_nanosecond_str) - 1);
563 // Set the corresponding cache required flag
564 cache_time_required = true;
565 cache_nanosecond_required = true;
566 break;
567 }
568 case PlaceholderType::Thread:
569 {
570 // Output cached thread Id string
571 record.raw.insert(record.raw.end(), std::begin(cache_thread_str), std::end(cache_thread_str) - 1);
572 // Set the corresponding cache required flag
573 cache_thread_required = true;
574 break;
575 }
576 case PlaceholderType::Level:
577 {
578 // Output cached level string
579 record.raw.insert(record.raw.end(), std::begin(cache_level_str), std::end(cache_level_str) - 1);
580 // Set the corresponding cache required flag
581 cache_level_required = true;
582 break;
583 }
584 case PlaceholderType::Logger:
585 {
586 // Output logger string
587 record.raw.insert(record.raw.end(), record.logger.begin(), record.logger.end());
588 break;
589 }
590 case PlaceholderType::Message:
591 {
592 // Output message string
593 record.raw.insert(record.raw.end(), record.message.begin(), record.message.end());
594 break;
595 }
596 }
597 }
598 }
599
600private:
601 std::string _pattern;
602 std::vector<Placeholder> _placeholders;
603
604 void AppendPattern(const std::string& pattern)
605 {
606 // Skip empty pattern
607 if (pattern.empty())
608 return;
609
610 // Insert or append pattern into placeholders collection
611 if (_placeholders.empty() || (_placeholders[_placeholders.size() - 1].type != PlaceholderType::String))
612 _placeholders.emplace_back(PlaceholderType::String, pattern);
613 else
614 _placeholders[_placeholders.size() - 1].value += pattern;
615 }
616
617 void AppendPlaceholder(const std::string& placeholder)
618 {
619 // Skip empty placeholder
620 if (placeholder.empty())
621 return;
622
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")
672 _placeholders.emplace_back(PlaceholderType::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());
679 else
680 AppendPattern("{" + placeholder + "}");
681 }
682
683 static void ConvertNumber(char* output, int number, size_t size)
684 {
685 // Prepare the output string
686 std::memset(output, '0', size);
687
688 // Calculate the output index
689 size_t index = size - 1;
690
691 // Output digits
692 while ((number >= 10) && (index != 0))
693 {
694 int a = number / 10;
695 int b = number % 10;
696 output[index--] = '0' + (char)b;
697 number = a;
698 }
699
700 // Output the last digit
701 output[index] = '0' + (char)number;
702 }
703
704 static void ConvertThread(char* output, uint64_t thread, size_t size)
705 {
706 const char* digits = "0123456789ABCDEF";
707
708 // Prepare the output string
709 std::memset(output, '0', size);
710
711 // Calculate the output index
712 size_t index = size - 1;
713
714 // Output digits
715 do
716 {
717 output[index--] = digits[thread & 0x0F];
718 } while (((thread >>= 4) != 0) && (index != 0));
719
720 // Output hex prefix
721 output[0] = '0';
722 output[1] = 'x';
723 }
724
725 static void ConvertTimezone(char* output, int64_t offset, size_t size)
726 {
727 // Prepare the output string
728 std::memset(output, '0', size);
729
730 // Calculate the output index
731 size_t index = size - 1;
732
733 // Output offset minutes
734 int64_t minutes = offset % 60;
735 if (minutes < 9)
736 {
737 output[index--] = '0' + (char)minutes;
738 --index;
739 }
740 else
741 {
742 output[index--] = '0' + (char)(minutes % 10);
743 minutes /= 10;
744 output[index--] = '0' + (char)minutes;
745 }
746
747 // Output ':' separator
748 output[index--] = ':';
749
750 // Output offset hours
751 int64_t hours = offset / 60;
752 if (hours < 9)
753 {
754 output[index] = '0' + (char)hours;
755 }
756 else
757 {
758 output[index--] = '0' + (char)(hours % 10);
759 hours /= 10;
760 output[index] = '0' + (char)hours;
761 }
762
763 // Output minus prefix
764 output[0] = (offset < 0) ? '-' : '+';
765 }
766
767 static void ConvertLevel(char* output, Level level, size_t size)
768 {
769 // Prepare the output string
770 std::memset(output, ' ', size);
771
772 switch (level)
773 {
774 case Level::NONE:
775 std::memcpy(output, "NONE", CppCommon::countof("NONE") - 1);
776 break;
777 case Level::FATAL:
778 std::memcpy(output, "FATAL", CppCommon::countof("FATAL") - 1);
779 break;
780 case Level::ERROR:
781 std::memcpy(output, "ERROR", CppCommon::countof("ERROR") - 1);
782 break;
783 case Level::WARN:
784 std::memcpy(output, "WARN", CppCommon::countof("WARN") - 1);
785 break;
786 case Level::INFO:
787 std::memcpy(output, "INFO", CppCommon::countof("INFO") - 1);
788 break;
789 case Level::DEBUG:
790 std::memcpy(output, "DEBUG", CppCommon::countof("DEBUG") - 1);
791 break;
792 case Level::ALL:
793 std::memcpy(output, "ALL", CppCommon::countof("ALL") - 1);
794 break;
795 default:
796 std::memcpy(output, "<\?\?\?>", CppCommon::countof("<\?\?\?>") - 1);
797 break;
798 }
799 }
800};
801
803
804TextLayout::TextLayout(const std::string& layout)
805{
806 // Check implementation storage parameters
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!");
810
811 // Create the implementation instance
812 new(&_storage)Impl(layout);
813}
814
816{
817 // Delete the implementation instance
818 reinterpret_cast<Impl*>(&_storage)->~Impl();
819}
820
821const std::string& TextLayout::pattern() const noexcept { return impl().pattern(); }
822
823void TextLayout::LayoutRecord(Record& record) { impl().LayoutRecord(record); }
824
825} // namespace CppLogging
Logging record.
Definition record.h:37
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.
Definition appender.h:15
Level
Logging level.
Definition level.h:18
Text layout definition.