WireCellToolkit
Wire Cell Simulation, Signal Process and Reconstruction Toolki for Liquid Argon Detectors
pattern_formatter.h
Go to the documentation of this file.
1 //
2 // Copyright(c) 2015 Gabi Melman.
3 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 //
5 
6 #pragma once
7 
10 #include "spdlog/details/os.h"
11 #include "spdlog/fmt/fmt.h"
12 #include "spdlog/formatter.h"
13 
14 #include <array>
15 #include <chrono>
16 #include <ctime>
17 #include <cctype>
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include <thread>
22 #include <utility>
23 #include <vector>
24 
25 namespace spdlog {
26 namespace details {
27 
28 // padding information.
30 {
31  enum pad_side
32  {
36  };
37 
38  padding_info() = default;
40  : width_(width)
41  , side_(side)
42  {
43  }
44 
45  bool enabled() const
46  {
47  return width_ != 0;
48  }
49  const size_t width_ = 0;
50  const pad_side side_ = left;
51 };
52 
54 {
55 public:
56  scoped_pad(size_t wrapped_size, padding_info &padinfo, fmt::memory_buffer &dest)
57  : padinfo_(padinfo)
58  , dest_(dest)
59  {
60 
61  if (padinfo_.width_ <= wrapped_size)
62  {
63  total_pad_ = 0;
64  return;
65  }
66 
67  total_pad_ = padinfo.width_ - wrapped_size;
68  if (padinfo_.side_ == padding_info::left)
69  {
70  pad_it(total_pad_);
71  total_pad_ = 0;
72  }
73  else if (padinfo_.side_ == padding_info::center)
74  {
75  auto half_pad = total_pad_ / 2;
76  auto reminder = total_pad_ & 1;
77  pad_it(half_pad);
78  total_pad_ = half_pad + reminder; // for the right side
79  }
80  }
81 
83  : scoped_pad(txt.size(), padinfo, dest)
84  {
85  }
86 
88  {
89  if (total_pad_)
90  {
91  pad_it(total_pad_);
92  }
93  }
94 
95 private:
96  void pad_it(size_t count)
97  {
98  // count = std::min(count, spaces_.size());
99  assert(count <= spaces_.size());
100  fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);
101  }
102 
103  const padding_info &padinfo_;
104  fmt::memory_buffer &dest_;
105  size_t total_pad_;
106  string_view_t spaces_{" "
107  " ",
108  128};
109 };
110 
112 {
113 public:
114  explicit flag_formatter(padding_info padinfo)
115  : padinfo_(padinfo)
116  {
117  }
118  flag_formatter() = default;
119  virtual ~flag_formatter() = default;
120  virtual void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) = 0;
121 
122 protected:
124 };
125 
127 // name & level pattern appender
130 {
131 public:
132  explicit name_formatter(padding_info padinfo)
133  : flag_formatter(padinfo)
134  {
135  }
136 
137  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
138  {
139  if (padinfo_.enabled())
140  {
141  scoped_pad p(*msg.logger_name, padinfo_, dest);
143  }
144  else
145  {
147  }
148  }
149 };
150 
151 // log level appender
153 {
154 public:
155  explicit level_formatter(padding_info padinfo)
156  : flag_formatter(padinfo)
157  {
158  }
159 
160  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
161  {
162  string_view_t &level_name = level::to_string_view(msg.level);
163  if (padinfo_.enabled())
164  {
165  scoped_pad p(level_name, padinfo_, dest);
166  fmt_helper::append_string_view(level_name, dest);
167  }
168  else
169  {
170  fmt_helper::append_string_view(level_name, dest);
171  }
172  }
173 };
174 
175 // short log level appender
177 {
178 public:
180  : flag_formatter(padinfo)
181  {
182  }
183 
184  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
185  {
186  string_view_t level_name{level::to_short_c_str(msg.level)};
187  scoped_pad p(level_name, padinfo_, dest);
188  fmt_helper::append_string_view(level_name, dest);
189  }
190 };
191 
193 // Date time pattern appenders
195 
196 static const char *ampm(const tm &t)
197 {
198  return t.tm_hour >= 12 ? "PM" : "AM";
199 }
200 
201 static int to12h(const tm &t)
202 {
203  return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
204 }
205 
206 // Abbreviated weekday name
207 static const char *days[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
209 {
210 public:
211  explicit a_formatter(padding_info padinfo)
212  : flag_formatter(padinfo)
213  {
214  }
215 
216  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
217  {
218  string_view_t field_value{days[tm_time.tm_wday]};
219  scoped_pad p(field_value, padinfo_, dest);
220  fmt_helper::append_string_view(field_value, dest);
221  }
222 };
223 
224 // Full weekday name
225 static const char *full_days[]{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
227 {
228 public:
229  explicit A_formatter(padding_info padinfo)
230  : flag_formatter(padinfo)
231  {
232  }
233 
234  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
235  {
236  string_view_t field_value{full_days[tm_time.tm_wday]};
237  scoped_pad p(field_value, padinfo_, dest);
238  fmt_helper::append_string_view(field_value, dest);
239  }
240 };
241 
242 // Abbreviated month
243 static const char *months[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
245 {
246 public:
247  explicit b_formatter(padding_info padinfo)
248  : flag_formatter(padinfo)
249  {
250  }
251 
252  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
253  {
254  string_view_t field_value{months[tm_time.tm_mon]};
255  scoped_pad p(field_value, padinfo_, dest);
256  fmt_helper::append_string_view(field_value, dest);
257  }
258 };
259 
260 // Full month name
261 static const char *full_months[]{
262  "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
264 {
265 public:
266  explicit B_formatter(padding_info padinfo)
267  : flag_formatter(padinfo)
268  {
269  }
270 
271  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
272  {
273  string_view_t field_value{full_months[tm_time.tm_mon]};
274  scoped_pad p(field_value, padinfo_, dest);
275  fmt_helper::append_string_view(field_value, dest);
276  }
277 };
278 
279 // Date and time representation (Thu Aug 23 15:35:46 2014)
280 class c_formatter final : public flag_formatter
281 {
282 public:
283  explicit c_formatter(padding_info padinfo)
284  : flag_formatter(padinfo)
285  {
286  }
287 
288  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
289  {
290  const size_t field_size = 24;
291  scoped_pad p(field_size, padinfo_, dest);
292 
293  fmt_helper::append_string_view(days[tm_time.tm_wday], dest);
294  dest.push_back(' ');
295  fmt_helper::append_string_view(months[tm_time.tm_mon], dest);
296  dest.push_back(' ');
297  fmt_helper::append_int(tm_time.tm_mday, dest);
298  dest.push_back(' ');
299  // time
300 
301  fmt_helper::pad2(tm_time.tm_hour, dest);
302  dest.push_back(':');
303  fmt_helper::pad2(tm_time.tm_min, dest);
304  dest.push_back(':');
305  fmt_helper::pad2(tm_time.tm_sec, dest);
306  dest.push_back(' ');
307  fmt_helper::append_int(tm_time.tm_year + 1900, dest);
308  }
309 };
310 
311 // year - 2 digit
312 class C_formatter final : public flag_formatter
313 {
314 public:
315  explicit C_formatter(padding_info padinfo)
316  : flag_formatter(padinfo)
317  {
318  }
319 
320  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
321  {
322  const size_t field_size = 2;
323  scoped_pad p(field_size, padinfo_, dest);
324  fmt_helper::pad2(tm_time.tm_year % 100, dest);
325  }
326 };
327 
328 // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
329 class D_formatter final : public flag_formatter
330 {
331 public:
332  explicit D_formatter(padding_info padinfo)
333  : flag_formatter(padinfo)
334  {
335  }
336 
337  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
338  {
339  const size_t field_size = 10;
340  scoped_pad p(field_size, padinfo_, dest);
341 
342  fmt_helper::pad2(tm_time.tm_mon + 1, dest);
343  dest.push_back('/');
344  fmt_helper::pad2(tm_time.tm_mday, dest);
345  dest.push_back('/');
346  fmt_helper::pad2(tm_time.tm_year % 100, dest);
347  }
348 };
349 
350 // year - 4 digit
351 class Y_formatter final : public flag_formatter
352 {
353 public:
354  explicit Y_formatter(padding_info padinfo)
355  : flag_formatter(padinfo){};
356 
357  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
358  {
359  const size_t field_size = 4;
360  scoped_pad p(field_size, padinfo_, dest);
361  fmt_helper::append_int(tm_time.tm_year + 1900, dest);
362  }
363 };
364 
365 // month 1-12
366 class m_formatter final : public flag_formatter
367 {
368 public:
369  explicit m_formatter(padding_info padinfo)
370  : flag_formatter(padinfo)
371  {
372  }
373 
374  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
375  {
376  const size_t field_size = 2;
377  scoped_pad p(field_size, padinfo_, dest);
378  fmt_helper::pad2(tm_time.tm_mon + 1, dest);
379  }
380 };
381 
382 // day of month 1-31
383 class d_formatter final : public flag_formatter
384 {
385 public:
386  explicit d_formatter(padding_info padinfo)
387  : flag_formatter(padinfo)
388  {
389  }
390 
391  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
392  {
393  const size_t field_size = 2;
394  scoped_pad p(field_size, padinfo_, dest);
395  fmt_helper::pad2(tm_time.tm_mday, dest);
396  }
397 };
398 
399 // hours in 24 format 0-23
400 class H_formatter final : public flag_formatter
401 {
402 public:
403  explicit H_formatter(padding_info padinfo)
404  : flag_formatter(padinfo)
405  {
406  }
407 
408  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
409  {
410  const size_t field_size = 2;
411  scoped_pad p(field_size, padinfo_, dest);
412  fmt_helper::pad2(tm_time.tm_hour, dest);
413  }
414 };
415 
416 // hours in 12 format 1-12
417 class I_formatter final : public flag_formatter
418 {
419 public:
420  explicit I_formatter(padding_info padinfo)
421  : flag_formatter(padinfo){};
422 
423  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
424  {
425  const size_t field_size = 2;
426  scoped_pad p(field_size, padinfo_, dest);
427  fmt_helper::pad2(to12h(tm_time), dest);
428  }
429 };
430 
431 // minutes 0-59
432 class M_formatter final : public flag_formatter
433 {
434 public:
435  explicit M_formatter(padding_info padinfo)
436  : flag_formatter(padinfo){};
437 
438  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
439  {
440  const size_t field_size = 2;
441  scoped_pad p(field_size, padinfo_, dest);
442  fmt_helper::pad2(tm_time.tm_min, dest);
443  }
444 };
445 
446 // seconds 0-59
447 class S_formatter final : public flag_formatter
448 {
449 public:
450  explicit S_formatter(padding_info padinfo)
451  : flag_formatter(padinfo){};
452 
453  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
454  {
455  const size_t field_size = 2;
456  scoped_pad p(field_size, padinfo_, dest);
457  fmt_helper::pad2(tm_time.tm_sec, dest);
458  }
459 };
460 
461 // milliseconds
462 class e_formatter final : public flag_formatter
463 {
464 public:
465  explicit e_formatter(padding_info padinfo)
466  : flag_formatter(padinfo){};
467 
468  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
469  {
470  auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
471  if (padinfo_.enabled())
472  {
473  const size_t field_size = 3;
474  scoped_pad p(field_size, padinfo_, dest);
475  fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
476  }
477  else
478  {
479  fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
480  }
481  }
482 };
483 
484 // microseconds
485 class f_formatter final : public flag_formatter
486 {
487 public:
488  explicit f_formatter(padding_info padinfo)
489  : flag_formatter(padinfo){};
490 
491  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
492  {
493  auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
494  if (padinfo_.enabled())
495  {
496  const size_t field_size = 6;
497  scoped_pad p(field_size, padinfo_, dest);
498  fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
499  }
500  else
501  {
502  fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
503  }
504  }
505 };
506 
507 // nanoseconds
508 class F_formatter final : public flag_formatter
509 {
510 public:
511  explicit F_formatter(padding_info padinfo)
512  : flag_formatter(padinfo){};
513 
514  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
515  {
516  auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
517  if (padinfo_.enabled())
518  {
519  const size_t field_size = 9;
520  scoped_pad p(field_size, padinfo_, dest);
521  fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
522  }
523  else
524  {
525  fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
526  }
527  }
528 };
529 
530 // seconds since epoch
531 class E_formatter final : public flag_formatter
532 {
533 public:
534  explicit E_formatter(padding_info padinfo)
535  : flag_formatter(padinfo){};
536 
537  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
538  {
539  const size_t field_size = 10;
540  scoped_pad p(field_size, padinfo_, dest);
541  auto duration = msg.time.time_since_epoch();
542  auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
543  fmt_helper::append_int(seconds, dest);
544  }
545 };
546 
547 // AM/PM
548 class p_formatter final : public flag_formatter
549 {
550 public:
551  explicit p_formatter(padding_info padinfo)
552  : flag_formatter(padinfo){};
553 
554  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
555  {
556  const size_t field_size = 2;
557  scoped_pad p(field_size, padinfo_, dest);
558  fmt_helper::append_string_view(ampm(tm_time), dest);
559  }
560 };
561 
562 // 12 hour clock 02:55:02 pm
563 class r_formatter final : public flag_formatter
564 {
565 public:
566  explicit r_formatter(padding_info padinfo)
567  : flag_formatter(padinfo){};
568 
569  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
570  {
571  const size_t field_size = 11;
572  scoped_pad p(field_size, padinfo_, dest);
573 
574  fmt_helper::pad2(to12h(tm_time), dest);
575  dest.push_back(':');
576  fmt_helper::pad2(tm_time.tm_min, dest);
577  dest.push_back(':');
578  fmt_helper::pad2(tm_time.tm_sec, dest);
579  dest.push_back(' ');
580  fmt_helper::append_string_view(ampm(tm_time), dest);
581  }
582 };
583 
584 // 24-hour HH:MM time, equivalent to %H:%M
585 class R_formatter final : public flag_formatter
586 {
587 public:
588  explicit R_formatter(padding_info padinfo)
589  : flag_formatter(padinfo){};
590 
591  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
592  {
593  const size_t field_size = 5;
594  scoped_pad p(field_size, padinfo_, dest);
595 
596  fmt_helper::pad2(tm_time.tm_hour, dest);
597  dest.push_back(':');
598  fmt_helper::pad2(tm_time.tm_min, dest);
599  }
600 };
601 
602 // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
603 class T_formatter final : public flag_formatter
604 {
605 public:
606  explicit T_formatter(padding_info padinfo)
607  : flag_formatter(padinfo){};
608 
609  void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
610  {
611  const size_t field_size = 8;
612  scoped_pad p(field_size, padinfo_, dest);
613 
614  fmt_helper::pad2(tm_time.tm_hour, dest);
615  dest.push_back(':');
616  fmt_helper::pad2(tm_time.tm_min, dest);
617  dest.push_back(':');
618  fmt_helper::pad2(tm_time.tm_sec, dest);
619  }
620 };
621 
622 // ISO 8601 offset from UTC in timezone (+-HH:MM)
623 class z_formatter final : public flag_formatter
624 {
625 public:
626  explicit z_formatter(padding_info padinfo)
627  : flag_formatter(padinfo){};
628 
629  const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
630 
631  z_formatter() = default;
632  z_formatter(const z_formatter &) = delete;
633  z_formatter &operator=(const z_formatter &) = delete;
634 
635  void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
636  {
637  const size_t field_size = 6;
638  scoped_pad p(field_size, padinfo_, dest);
639 
640 #ifdef _WIN32
641  int total_minutes = get_cached_offset(msg, tm_time);
642 #else
643  // No need to chache under gcc,
644  // it is very fast (already stored in tm.tm_gmtoff)
645  (void)(msg);
646  int total_minutes = os::utc_minutes_offset(tm_time);
647 #endif
648  bool is_negative = total_minutes < 0;
649  if (is_negative)
650  {
651  total_minutes = -total_minutes;
652  dest.push_back('-');
653  }
654  else
655  {
656  dest.push_back('+');
657  }
658 
659  fmt_helper::pad2(total_minutes / 60, dest); // hours
660  dest.push_back(':');
661  fmt_helper::pad2(total_minutes % 60, dest); // minutes
662  }
663 
664 private:
665  log_clock::time_point last_update_{std::chrono::seconds(0)};
666 #ifdef _WIN32
667  int offset_minutes_{0};
668 
669  int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
670  {
671  if (msg.time - last_update_ >= cache_refresh)
672  {
673  offset_minutes_ = os::utc_minutes_offset(tm_time);
674  last_update_ = msg.time;
675  }
676  return offset_minutes_;
677  }
678 #endif
679 };
680 
681 // Thread id
682 class t_formatter final : public flag_formatter
683 {
684 public:
685  explicit t_formatter(padding_info padinfo)
686  : flag_formatter(padinfo){};
687 
688  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
689  {
690  if (padinfo_.enabled())
691  {
692  const auto field_size = fmt_helper::count_digits(msg.thread_id);
693  scoped_pad p(field_size, padinfo_, dest);
695  }
696  else
697  {
699  }
700  }
701 };
702 
703 // Current pid
704 class pid_formatter final : public flag_formatter
705 {
706 public:
707  explicit pid_formatter(padding_info padinfo)
708  : flag_formatter(padinfo){};
709 
710  void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
711  {
712  const auto pid = static_cast<uint32_t>(details::os::pid());
713  if (padinfo_.enabled())
714  {
715  auto field_size = fmt_helper::count_digits(pid);
716  scoped_pad p(field_size, padinfo_, dest);
718  }
719  else
720  {
722  }
723  }
724 };
725 
726 // message counter formatter
727 class i_formatter final : public flag_formatter
728 {
729 public:
730  explicit i_formatter(padding_info padinfo)
731  : flag_formatter(padinfo){};
732 
733  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
734  {
735  const size_t field_size = 6;
736  scoped_pad p(field_size, padinfo_, dest);
737  fmt_helper::pad6(msg.msg_id, dest);
738  }
739 };
740 
741 class v_formatter final : public flag_formatter
742 {
743 public:
744  explicit v_formatter(padding_info padinfo)
745  : flag_formatter(padinfo){};
746 
747  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
748  {
749  if (padinfo_.enabled())
750  {
751  scoped_pad p(msg.payload, padinfo_, dest);
753  }
754  else
755  {
757  }
758  }
759 };
760 
761 class ch_formatter final : public flag_formatter
762 {
763 public:
764  explicit ch_formatter(char ch)
765  : ch_(ch)
766  {
767  }
768 
769  void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
770  {
771  const size_t field_size = 1;
772  scoped_pad p(field_size, padinfo_, dest);
773  dest.push_back(ch_);
774  }
775 
776 private:
777  char ch_;
778 };
779 
780 // aggregate user chars to display as is
782 {
783 public:
784  aggregate_formatter() = default;
785 
786  void add_ch(char ch)
787  {
788  str_ += ch;
789  }
790  void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
791  {
792  fmt_helper::append_string_view(str_, dest);
793  }
794 
795 private:
796  std::string str_;
797 };
798 
799 // mark the color range. expect it to be in the form of "%^colored text%$"
801 {
802 public:
804  : flag_formatter(padinfo)
805  {
806  }
807 
808  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
809  {
810  msg.color_range_start = dest.size();
811  }
812 };
814 {
815 public:
817  : flag_formatter(padinfo)
818  {
819  }
820 
821  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
822  {
823  msg.color_range_end = dest.size();
824  }
825 };
826 
827 // print source location
829 {
830 public:
832  : flag_formatter(padinfo){};
833 
834  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
835  {
836  if (msg.source.empty())
837  {
838  return;
839  }
840  if (padinfo_.enabled())
841  {
842  const auto text_size = std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1;
843  scoped_pad p(text_size, padinfo_, dest);
845  dest.push_back(':');
847  }
848  else
849  {
851  dest.push_back(':');
853  }
854  }
855 };
856 // print source filename
858 {
859 public:
861  : flag_formatter(padinfo){};
862 
863  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
864  {
865  if (msg.source.empty())
866  {
867  return;
868  }
869  scoped_pad p(msg.source.filename, padinfo_, dest);
871  }
872 };
873 
875 {
876 public:
878  : flag_formatter(padinfo){};
879 
880  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
881  {
882  if (msg.source.empty())
883  {
884  return;
885  }
886  if (padinfo_.enabled())
887  {
888  auto field_size = fmt_helper::count_digits(msg.source.line);
889  scoped_pad p(field_size, padinfo_, dest);
891  }
892  else
893  {
895  }
896  }
897 };
898 // print source funcname
900 {
901 public:
903  : flag_formatter(padinfo){};
904 
905  void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
906  {
907  if (msg.source.empty())
908  {
909  return;
910  }
911  scoped_pad p(msg.source.funcname, padinfo_, dest);
913  }
914 };
915 
916 // Full info formatter
917 // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
918 class full_formatter final : public flag_formatter
919 {
920 public:
921  explicit full_formatter(padding_info padinfo)
922  : flag_formatter(padinfo)
923  {
924  }
925 
926  void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
927  {
928  using std::chrono::duration_cast;
929  using std::chrono::milliseconds;
930  using std::chrono::seconds;
931 
932 #ifndef SPDLOG_NO_DATETIME
933 
934  // cache the date/time part for the next second.
935  auto duration = msg.time.time_since_epoch();
936  auto secs = duration_cast<seconds>(duration);
937 
938  if (cache_timestamp_ != secs || cached_datetime_.size() == 0)
939  {
940  cached_datetime_.clear();
941  cached_datetime_.push_back('[');
942  fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
943  cached_datetime_.push_back('-');
944 
945  fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
946  cached_datetime_.push_back('-');
947 
948  fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
949  cached_datetime_.push_back(' ');
950 
951  fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
952  cached_datetime_.push_back(':');
953 
954  fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
955  cached_datetime_.push_back(':');
956 
957  fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
958  cached_datetime_.push_back('.');
959 
960  cache_timestamp_ = secs;
961  }
962  fmt_helper::append_buf(cached_datetime_, dest);
963 
964  auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
965  fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
966  dest.push_back(']');
967  dest.push_back(' ');
968 
969 #else // no datetime needed
970  (void)tm_time;
971 #endif
972 
973 #ifndef SPDLOG_NO_NAME
974  if (!msg.logger_name->empty())
975  {
976  dest.push_back('[');
977  // fmt_helper::append_str(*msg.logger_name, dest);
979  dest.push_back(']');
980  dest.push_back(' ');
981  }
982 #endif
983 
984  dest.push_back('[');
985  // wrap the level name with color
986  msg.color_range_start = dest.size();
987  // fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
989  msg.color_range_end = dest.size();
990  dest.push_back(']');
991  dest.push_back(' ');
992 
993  // add source location if present
994  if (!msg.source.empty())
995  {
996  dest.push_back('[');
998  dest.push_back(':');
1000  dest.push_back(']');
1001  dest.push_back(' ');
1002  }
1003  // fmt_helper::append_string_view(msg.msg(), dest);
1005  }
1006 
1007 private:
1008  std::chrono::seconds cache_timestamp_{0};
1009  fmt::basic_memory_buffer<char, 128> cached_datetime_;
1010 };
1011 
1012 } // namespace details
1013 
1014 class pattern_formatter final : public formatter
1015 {
1016 public:
1018  std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol)
1019  : pattern_(std::move(pattern))
1020  , eol_(std::move(eol))
1021  , pattern_time_type_(time_type)
1022  , last_log_secs_(0)
1023  {
1024  std::memset(&cached_tm_, 0, sizeof(cached_tm_));
1025  compile_pattern_(pattern_);
1026  }
1027 
1028  // use by default full formatter for if pattern is not given
1029  explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol)
1030  : pattern_("%+")
1031  , eol_(std::move(eol))
1032  , pattern_time_type_(time_type)
1033  , last_log_secs_(0)
1034  {
1035  std::memset(&cached_tm_, 0, sizeof(cached_tm_));
1036  formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{}));
1037  }
1038 
1039  pattern_formatter(const pattern_formatter &other) = delete;
1040  pattern_formatter &operator=(const pattern_formatter &other) = delete;
1041 
1042  std::unique_ptr<formatter> clone() const override
1043  {
1044  return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_);
1045  }
1046 
1047  void format(const details::log_msg &msg, fmt::memory_buffer &dest) override
1048  {
1049 #ifndef SPDLOG_NO_DATETIME
1050  auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
1051  if (secs != last_log_secs_)
1052  {
1053  cached_tm_ = get_time_(msg);
1054  last_log_secs_ = secs;
1055  }
1056 #endif
1057  for (auto &f : formatters_)
1058  {
1059  f->format(msg, cached_tm_, dest);
1060  }
1061  // write eol
1063  }
1064 
1065 private:
1066  std::string pattern_;
1067  std::string eol_;
1068  pattern_time_type pattern_time_type_;
1069  std::tm cached_tm_;
1070  std::chrono::seconds last_log_secs_;
1071 
1072  std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
1073 
1074  std::tm get_time_(const details::log_msg &msg)
1075  {
1076  if (pattern_time_type_ == pattern_time_type::local)
1077  {
1078  return details::os::localtime(log_clock::to_time_t(msg.time));
1079  }
1080  return details::os::gmtime(log_clock::to_time_t(msg.time));
1081  }
1082 
1083  void handle_flag_(char flag, details::padding_info padding)
1084  {
1085  switch (flag)
1086  {
1087 
1088  case ('+'): // default formatter
1089  formatters_.push_back(details::make_unique<details::full_formatter>(padding));
1090  break;
1091 
1092  case 'n': // logger name
1093  formatters_.push_back(details::make_unique<details::name_formatter>(padding));
1094  break;
1095 
1096  case 'l': // level
1097  formatters_.push_back(details::make_unique<details::level_formatter>(padding));
1098  break;
1099 
1100  case 'L': // short level
1101  formatters_.push_back(details::make_unique<details::short_level_formatter>(padding));
1102  break;
1103 
1104  case ('t'): // thread id
1105  formatters_.push_back(details::make_unique<details::t_formatter>(padding));
1106  break;
1107 
1108  case ('v'): // the message text
1109  formatters_.push_back(details::make_unique<details::v_formatter>(padding));
1110  break;
1111 
1112  case ('a'): // weekday
1113  formatters_.push_back(details::make_unique<details::a_formatter>(padding));
1114  break;
1115 
1116  case ('A'): // short weekday
1117  formatters_.push_back(details::make_unique<details::A_formatter>(padding));
1118  break;
1119 
1120  case ('b'):
1121  case ('h'): // month
1122  formatters_.push_back(details::make_unique<details::b_formatter>(padding));
1123  break;
1124 
1125  case ('B'): // short month
1126  formatters_.push_back(details::make_unique<details::B_formatter>(padding));
1127  break;
1128 
1129  case ('c'): // datetime
1130  formatters_.push_back(details::make_unique<details::c_formatter>(padding));
1131  break;
1132 
1133  case ('C'): // year 2 digits
1134  formatters_.push_back(details::make_unique<details::C_formatter>(padding));
1135  break;
1136 
1137  case ('Y'): // year 4 digits
1138  formatters_.push_back(details::make_unique<details::Y_formatter>(padding));
1139  break;
1140 
1141  case ('D'):
1142  case ('x'): // datetime MM/DD/YY
1143  formatters_.push_back(details::make_unique<details::D_formatter>(padding));
1144  break;
1145 
1146  case ('m'): // month 1-12
1147  formatters_.push_back(details::make_unique<details::m_formatter>(padding));
1148  break;
1149 
1150  case ('d'): // day of month 1-31
1151  formatters_.push_back(details::make_unique<details::d_formatter>(padding));
1152  break;
1153 
1154  case ('H'): // hours 24
1155  formatters_.push_back(details::make_unique<details::H_formatter>(padding));
1156  break;
1157 
1158  case ('I'): // hours 12
1159  formatters_.push_back(details::make_unique<details::I_formatter>(padding));
1160  break;
1161 
1162  case ('M'): // minutes
1163  formatters_.push_back(details::make_unique<details::M_formatter>(padding));
1164  break;
1165 
1166  case ('S'): // seconds
1167  formatters_.push_back(details::make_unique<details::S_formatter>(padding));
1168  break;
1169 
1170  case ('e'): // milliseconds
1171  formatters_.push_back(details::make_unique<details::e_formatter>(padding));
1172  break;
1173 
1174  case ('f'): // microseconds
1175  formatters_.push_back(details::make_unique<details::f_formatter>(padding));
1176  break;
1177 
1178  case ('F'): // nanoseconds
1179  formatters_.push_back(details::make_unique<details::F_formatter>(padding));
1180  break;
1181 
1182  case ('E'): // seconds since epoch
1183  formatters_.push_back(details::make_unique<details::E_formatter>(padding));
1184  break;
1185 
1186  case ('p'): // am/pm
1187  formatters_.push_back(details::make_unique<details::p_formatter>(padding));
1188  break;
1189 
1190  case ('r'): // 12 hour clock 02:55:02 pm
1191  formatters_.push_back(details::make_unique<details::r_formatter>(padding));
1192  break;
1193 
1194  case ('R'): // 24-hour HH:MM time
1195  formatters_.push_back(details::make_unique<details::R_formatter>(padding));
1196  break;
1197 
1198  case ('T'):
1199  case ('X'): // ISO 8601 time format (HH:MM:SS)
1200  formatters_.push_back(details::make_unique<details::T_formatter>(padding));
1201  break;
1202 
1203  case ('z'): // timezone
1204  formatters_.push_back(details::make_unique<details::z_formatter>(padding));
1205  break;
1206 
1207  case ('P'): // pid
1208  formatters_.push_back(details::make_unique<details::pid_formatter>(padding));
1209  break;
1210 
1211 #ifdef SPDLOG_ENABLE_MESSAGE_COUNTER
1212  case ('i'):
1213  formatters_.push_back(details::make_unique<details::i_formatter>(padding));
1214  break;
1215 #endif
1216  case ('^'): // color range start
1217  formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));
1218  break;
1219 
1220  case ('$'): // color range end
1221  formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));
1222  break;
1223 
1224  case ('@'): // source location (filename:filenumber)
1225  formatters_.push_back(details::make_unique<details::source_location_formatter>(padding));
1226  break;
1227 
1228  case ('s'): // source filename
1229  formatters_.push_back(details::make_unique<details::source_filename_formatter>(padding));
1230  break;
1231 
1232  case ('#'): // source line number
1233  formatters_.push_back(details::make_unique<details::source_linenum_formatter>(padding));
1234  break;
1235 
1236  case ('!'): // source funcname
1237  formatters_.push_back(details::make_unique<details::source_funcname_formatter>(padding));
1238  break;
1239 
1240  case ('%'): // % char
1241  formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
1242  break;
1243 
1244  default: // Unknown flag appears as is
1245  auto unknown_flag = details::make_unique<details::aggregate_formatter>();
1246  unknown_flag->add_ch('%');
1247  unknown_flag->add_ch(flag);
1248  formatters_.push_back((std::move(unknown_flag)));
1249  break;
1250  }
1251  }
1252 
1253  // Extract given pad spec (e.g. %8X)
1254  // Advance the given it pass the end of the padding spec found (if any)
1255  // Return padding.
1256  details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)
1257  {
1258  using details::padding_info;
1259  using details::scoped_pad;
1260  const size_t max_width = 128;
1261  if (it == end)
1262  {
1263  return padding_info{};
1264  }
1265 
1267  switch (*it)
1268  {
1269  case '-':
1270  side = padding_info::right;
1271  ++it;
1272  break;
1273  case '=':
1274  side = padding_info::center;
1275  ++it;
1276  break;
1277  default:
1279  break;
1280  }
1281 
1282  if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
1283  {
1284  return padding_info{0, side};
1285  }
1286 
1287  auto width = static_cast<size_t>(*it - '0');
1288  for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it)
1289  {
1290  auto digit = static_cast<size_t>(*it - '0');
1291  width = width * 10 + digit;
1292  }
1293  return details::padding_info{std::min<size_t>(width, max_width), side};
1294  }
1295 
1296  void compile_pattern_(const std::string &pattern)
1297  {
1298  auto end = pattern.end();
1299  std::unique_ptr<details::aggregate_formatter> user_chars;
1300  formatters_.clear();
1301  for (auto it = pattern.begin(); it != end; ++it)
1302  {
1303  if (*it == '%')
1304  {
1305  if (user_chars) // append user chars found so far
1306  {
1307  formatters_.push_back(std::move(user_chars));
1308  }
1309 
1310  auto padding = handle_padspec_(++it, end);
1311 
1312  if (it != end)
1313  {
1314  handle_flag_(*it, padding);
1315  }
1316  else
1317  {
1318  break;
1319  }
1320  }
1321  else // chars not following the % sign should be displayed as is
1322  {
1323  if (!user_chars)
1324  {
1325  user_chars = details::make_unique<details::aggregate_formatter>();
1326  }
1327  user_chars->add_ch(*it);
1328  }
1329  }
1330  if (user_chars) // append raw chars found so far
1331  {
1332  formatters_.push_back(std::move(user_chars));
1333  }
1334  }
1335 };
1336 } // namespace spdlog
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
R_formatter(padding_info padinfo)
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
basic_memory_buffer< char > memory_buffer
Definition: format.h:553
std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
Definition: os.h:92
pattern_formatter(std::string pattern, pattern_time_type time_type=pattern_time_type::local, std::string eol=spdlog::details::os::default_eol)
const std::string * logger_name
Definition: log_msg.h:41
pid_formatter(padding_info padinfo)
f_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
C_formatter(padding_info padinfo)
b_formatter(padding_info padinfo)
scoped_pad(spdlog::string_view_t txt, padding_info &padinfo, fmt::memory_buffer &dest)
name_formatter(padding_info padinfo)
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
H_formatter(padding_info padinfo)
void append_int(T n, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:40
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
If we are still before C++14, supply the fodder for doing the "indices trick".
Definition: format.h:297
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void pad3(T n, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:90
void append_buf(const fmt::basic_memory_buffer< char, Buffer_Size1 > &buf, fmt::basic_memory_buffer< char, Buffer_Size2 > &dest)
Definition: fmt_helper.h:23
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void pad6(T n, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:96
const char * funcname
Definition: common.h:226
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
F_formatter(padding_info padinfo)
int utc_minutes_offset(const std::tm &tm=details::os::localtime())
Definition: os.h:249
const char * filename
Definition: common.h:224
t_formatter(padding_info padinfo)
Definition: async.h:27
scoped_pad(size_t wrapped_size, padding_info &padinfo, fmt::memory_buffer &dest)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
flag_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
E_formatter(padding_info padinfo)
S_formatter(padding_info padinfo)
std::basic_string< FMT_CHAR(S)> format(const S &format_str, const Args &... args)
Definition: core.h:1454
FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end())
Definition: format.h:257
level::level_enum level
Definition: log_msg.h:42
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
c_formatter(padding_info padinfo)
pattern_time_type
Definition: common.h:163
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
A_formatter(padding_info padinfo)
void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:30
padding_info(size_t width, padding_info::pad_side side)
a_formatter(padding_info padinfo)
Y_formatter(padding_info padinfo)
void pad9(T n, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:102
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
string_view_t & to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
Definition: common.h:132
r_formatter(padding_info padinfo)
T_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
I_formatter(padding_info padinfo)
z_formatter(padding_info padinfo)
void format(const details::log_msg &msg, fmt::memory_buffer &dest) override
D_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
FMT_CONSTEXPR std::enable_if< std::numeric_limits< T >::is_signed, bool >::type is_negative(T value)
Definition: format.h:727
fmt::string_view string_view_t
Definition: common.h:88
level_formatter(padding_info padinfo)
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
pattern_formatter(pattern_time_type time_type=pattern_time_type::local, std::string eol=spdlog::details::os::default_eol)
void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
i_formatter(padding_info padinfo)
std::unique_ptr< formatter > clone() const override
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
const string_view_t payload
Definition: log_msg.h:52
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
m_formatter(padding_info padinfo)
B_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
const char * to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
Definition: common.h:137
v_formatter(padding_info padinfo)
std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
Definition: os.h:73
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
Definition: common.h:220
void pad2(int n, fmt::basic_memory_buffer< char, Buffer_Size > &dest)
Definition: fmt_helper.h:54
d_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
M_formatter(padding_info padinfo)
unsigned count_digits(T n)
Definition: fmt_helper.h:47
p_formatter(padding_info padinfo)
log_clock::time_point time
Definition: log_msg.h:43
e_formatter(padding_info padinfo)
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
uint32_t line
Definition: common.h:225
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
full_formatter(padding_info padinfo)
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override