CppLogging  1.0.4.0
C++ Logging Library
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 
18 namespace CppLogging {
19 
21 
22 class 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 
65 public:
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  }
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 
600 private:
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 
804 TextLayout::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 
821 const std::string& TextLayout::pattern() const noexcept { return impl().pattern(); }
822 
823 void 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
@ FATAL
Log fatal errors.
@ WARN
Log warnings.
@ INFO
Log information.
@ ALL
Log everything.
@ NONE
Log nothing.
@ ERROR
Log errors.
@ DEBUG
Log debug.
Text layout definition.