clutchlog  0.13
clutchlog.h
Go to the documentation of this file.
1 #pragma once
2 #ifndef CLUTCHLOG_H
3 #define CLUTCHLOG_H
5 
7 #include <ciso646>
8  #ifdef FSEXPERIMENTAL
9  #include <experimental/filesystem>
10  namespace fs = std::experimental::filesystem;
11 #else
12  #include <filesystem>
13  namespace fs = std::filesystem;
14 #endif
15 
16 #include <iostream>
17 #include <sstream>
18 #include <fstream>
19 #include <cassert>
20 #include <cstdlib>
21 #include <string>
22 #include <limits>
23 #include <regex>
24 #include <map>
25 
27 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
28  #include <execinfo.h> // execinfo
29  #include <stdlib.h> // getenv
30  #include <libgen.h> // basename
31  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
32 #else
33  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
34 #endif
35 
37 #if __has_include(<sys/ioctl.h>) && __has_include(<stdio.h>) && __has_include(<unistd.h>)
38  #include <sys/ioctl.h>
39  #include <stdio.h>
40  #include <unistd.h>
41  #define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 1
42 #else
43  #define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 0
44 #endif
45 
46 
47 /**********************************************************************
48  * Enable by default in Debug builds.
49  **********************************************************************/
50 #ifndef WITH_CLUTCHLOG
51  #ifndef NDEBUG
52  #define WITH_CLUTCHLOG
54  #endif
55 #endif
56 
57 /**********************************************************************
58  * Macros definitions
59  **********************************************************************/
60 #ifdef WITH_CLUTCHLOG
61 
65 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
66  #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
68 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
69 
76 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
78 
80 #ifndef NDEBUG
81  #define CLUTCHLOG( LEVEL, WHAT ) do { \
82  auto& clutchlog__logger = clutchlog::logger(); \
83  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
84  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
85  } while(0)
86 #else // not Debug build.
87  #define CLUTCHLOG( LEVEL, WHAT ) do { \
88  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
89  auto& clutchlog__logger = clutchlog::logger(); \
90  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
91  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
92  } \
93  } while(0)
94 #endif // NDEBUG
95 
97 #ifndef NDEBUG
98  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
99  auto& clutchlog__logger = clutchlog::logger(); \
100  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
101  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
102  } while(0)
103 #else // not Debug build.
104  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
105  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
106  auto& clutchlog__logger = clutchlog::logger(); \
107  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
108  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
109  } \
110  } while(0)
111 #endif // NDEBUG
112 
114 #ifndef NDEBUG
115  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
116  auto& clutchlog__logger = clutchlog::logger(); \
117  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
118  if(clutchlog__scope.matches) { \
119  FUNC(__VA_ARGS__); \
120  } \
121  } while(0)
122 #else // not Debug build.
123  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
124  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
125  auto& clutchlog__logger = clutchlog::logger(); \
126  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
127  if(clutchlog__scope.matches) { \
128  FUNC(__VA_ARGS__); \
129  } \
130  } \
131  } while(0)
132 #endif // NDEBUG
133 
135 #ifndef NDEBUG
136  #define CLUTCHCODE( LEVEL, ... ) do { \
137  auto& clutchlog__logger = clutchlog::logger(); \
138  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
139  if(clutchlog__scope.matches) { \
140  __VA_ARGS__ \
141  } \
142  } while(0)
143 #else // not Debug build.
144  #define CLUTCHCODE( LEVEL, CODE ) do { \
145  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
146  auto& clutchlog__logger = clutchlog::logger(); \
147  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
148  if(clutchlog__scope.matches) { \
149  CODE \
150  } \
151  } \
152  } while(0)
153 #endif // NDEBUG
154 
157 #else // not WITH_CLUTCHLOG
158  // Disabled macros can still be called in Release builds.
159  #define CLUTCHLOG( LEVEL, WHAT ) do {/*nothing*/} while(0)
160  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {/*nothing*/} while(0)
161  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do {/*nothing*/} while(0)
162  #define CLUTCHCODE( LEVEL, CODE ) do {/*nothing*/} while(0)
163 #endif // WITH_CLUTCHLOG
164 
165 /**********************************************************************
166  * Implementation
167  **********************************************************************/
168 
169 #ifdef WITH_CLUTCHLOG
170 
178 {
179  protected:
180 
185  #ifndef NDEBUG
186  #ifndef CLUTCHLOG_DEFAULT_FORMAT
187  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 // Enables: name, depth and depth_marks
189  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1 // Enables: hfill
190  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\n"
191  #else
192  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
193  #endif
194  #else
195  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
196  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg} {hfill} {func} @ {file}:{line}\n"
197  #else
198  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
199  #endif
200  #endif
201  #endif
202  #else
203  #ifndef CLUTCHLOG_DEFAULT_FORMAT
204  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
206  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func}\n"
207  #else
208  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func}\n"
209  #endif
210  #endif
211  #endif
212  static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
214 
215  #ifndef NDEBUG
216  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
217  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
219  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
220  #else
221  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
222  #endif
223  #endif // CLUTCHDUMP_DEFAULT_FORMAT
224  #else
225  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
226  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
228  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth})"
229  #else
230  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func}"
231  #endif
232  #endif // CLUTCHDUMP_DEFAULT_FORMAT
233  #endif
234  static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
236 
237  #ifndef CLUTCHDUMP_DEFAULT_SEP
238  #define CLUTCHDUMP_DEFAULT_SEP "\n"
240  #endif // CLUTCHDUMP_DEFAULT_SEP
241  static inline std::string dump_default_sep = CLUTCHDUMP_DEFAULT_SEP;
243 
244  #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
245  #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
247  #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
248  static inline std::string default_depth_mark = CLUTCHLOG_DEFAULT_DEPTH_MARK;
250 
251  #ifndef CLUTCHLOG_STRIP_CALLS
252  #define CLUTCHLOG_STRIP_CALLS 5
254  #endif // CLUTCHLOG_STRIP_CALLS
255  static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
257 
258  #ifndef CLUTCHLOG_DEFAULT_HFILL_MARK
259  #define CLUTCHLOG_DEFAULT_HFILL_MARK '.'
261  #endif // CLUTCHLOG_DEFAULT_HFILL_MARK
264 
265 
266  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
267  #ifndef CLUTCHLOG_DEFAULT_HFILL_MAX
268  #define CLUTCHLOG_DEFAULT_HFILL_MAX 300
269  #endif
270  #ifndef CLUTCHLOG_DEFAULT_HFILL_MIN
271  #define CLUTCHLOG_DEFAULT_HFILL_MIN 150
272  #endif
273  #endif
274  static inline size_t default_hfill_max = CLUTCHLOG_DEFAULT_HFILL_MAX;
277  static inline size_t default_hfill_min = CLUTCHLOG_DEFAULT_HFILL_MIN;
278 
279  // NOTE: there is no CLUTCHLOG_HFILL_STYLE for defaulting,
280  // but you can still set `hfill_style(...)` on the logger singleton.
281  /* @} DefaultConfig */
282  /* @} */
283 
284 
285  public:
286 
296  static clutchlog& logger()
297  {
298  static clutchlog instance;
299  return instance;
300  }
301 
303  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
304 
366  class fmt {
367  public:
369  enum class ansi {
371  colors_16 = -1, // Not supposed to be casted.
373  colors_256 = 5, // Casted as short in color::operator<<.
375  colors_16M = 2 // Casted as short in color::operator<<
376  } mode;
377 
379  enum class typo {
380  reset = 0,
381  bold = 1,
382  underline = 4,
383  inverse = 7,
384  none = -1
385  } style;
386 
389  enum class fg {
391  black = 30,
392  red = 31,
393  green = 32,
394  yellow = 33,
395  blue = 34,
396  magenta = 35,
397  cyan = 36,
398  white = 37,
399  bright_black = 90,
400  bright_red = 91,
401  bright_green = 92,
402  bright_yellow = 93,
403  bright_blue = 94,
404  bright_magenta = 95,
405  bright_cyan = 96,
406  bright_white = 97,
407  none = -1
408  } fore;
409 
411  enum class bg {
412  black = 40,
413  red = 41,
414  green = 42,
415  yellow = 43,
416  blue = 44,
417  magenta = 45,
418  cyan = 46,
419  white = 47,
420  bright_black = 100,
421  bright_red = 101,
422  bright_green = 102,
423  bright_yellow = 103,
424  bright_blue = 104,
425  bright_magenta = 105,
426  bright_cyan = 106,
427  bright_white = 107,
428  none = -1
429  } back;
430 
431  protected:
433  friend std::ostream& operator<<(std::ostream& os, const std::tuple<fg,bg,typo>& fbs)
434  {
435  auto [f,b,s] = fbs;
436  std::vector<short> codes; codes.reserve(3);
437  if(f != fg::none) { codes.push_back(static_cast<short>(f));}
438  if(b != bg::none) { codes.push_back(static_cast<short>(b));}
439  if(s != typo::none) { codes.push_back(static_cast<short>(s));}
440  if(codes.size() == 0) {
441  return os;
442 
443  } else {
444  os << "\033[";
445  os << codes[0];
446  for(size_t i=1; i < codes.size(); ++i) {
447  os << ";" << codes[i];
448  }
449  os << "m";
450  }
451  return os;
452  }
453 
455  friend std::ostream& operator<<(std::ostream& os, const typo& s)
456  {
457  if(s != typo::none) {
458  os << "\033[" << static_cast<short>(s) << "m";
459  }
460  return os;
461  }
462 
465  protected:
470  struct color {
471  ansi mode; // Not const to allow for the implicit copy assignemnt operator.
472 
474  enum class ground { // idem.
475  fore = 38,
476  back = 48
477  } type;
478 
484  color(ansi a, ground g) : mode(a), type(g) {}
485 
487  virtual bool is_set() const = 0;
488 
490  virtual std::ostream& print_on( std::ostream& os) const = 0;
491 
493  friend std::ostream& operator<<(std::ostream& os, const color& c)
494  {
495  if(c.is_set()) {
496  os << "\033[" << static_cast<short>(c.type) << ";" << static_cast<short>(c.mode) << ";";
497  c.print_on(os);
498  os << "m";
499  }
500  return os;
501  }
502  };
503 
504  // There is no color_16 because it would be the same as color_256, only with different indices,
505  // hence making it more complicated for the user to select the right constructor.
506  // Here, we just use enum for 16 colors, and indices for 256 colors.
507 
509  struct color_256 : public color {
513  short index;
514 
518  color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
519 
525  color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {assert(-1 <= i and i <= 255);}
526 
528  bool is_set() const {return index > -1;}
529 
531  std::ostream& print_on( std::ostream& os) const
532  {
533  os << index;
534  return os;
535  }
536  };
537 
539  struct fg_256 : public color_256 {
541  fg_256() : color_256(ground::fore) {}
542 
546  fg_256(const short f) : color_256(ground::fore, f) {}
547 
551  fg_256(const fg&) : color_256(ground::fore, -1) {}
552 
553  } fore_256;
554 
556  struct bg_256 : public color_256 {
558  bg_256() : color_256(ground::back) {}
559 
563  bg_256(const short b) : color_256(ground::back, b) {}
564 
568  bg_256(const bg&) : color_256(ground::back, -1) {}
569 
570  } back_256;
571 
573  struct color_16M : public color {
577  short red, green, blue;
578 
582  color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
583 
591  color_16M(ground t, short r, short g, short b)
592  : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
593 
601  color_16M(ground t, const std::string& srgb) : color(ansi::colors_16M, t)
602  {
603  assert(srgb.size() == 7);
604  if(srgb.size() != 7) {
605  red = -1;
606  green = -1;
607  blue = -1;
608  } else {
609  char i = 0;
610  if(srgb.at(0) == '#') {
611  i = 1;
612  }
613  std::istringstream(srgb.substr(0+i,2)) >> std::hex >> red;
614  std::istringstream(srgb.substr(2+i,2)) >> std::hex >> green;
615  std::istringstream(srgb.substr(4+i,2)) >> std::hex >> blue;
616  }
617  assert(-1 <= red and red <= 255);
618  assert(-1 <= green and green <= 255);
619  assert(-1 <= blue and blue <= 255);
620  }
621 
623  bool is_set() const {return red > -1 and green > -1 and blue > -1;}
624 
626  std::ostream& print_on( std::ostream& os) const
627  {
628  os << red << ";" << green << ";" << blue;
629  return os;
630  }
631  };
632 
634  struct fg_16M : public color_16M {
636  fg_16M() : color_16M(ground::fore) {}
637 
646  fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
647 
654  fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
655 
659  fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
660 
661  } fore_16M;
662 
664  struct bg_16M : public color_16M {
666  bg_16M() : color_16M(ground::back) {}
667 
676  bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
677 
684  bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
685 
689  bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
690 
691  } back_16M;
692 
695  public:
697  fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
698 
701  fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
702  fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
703  fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
704  fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
705  fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
706  fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
711  fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
712  fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
713  fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
718  fmt(const short fr, const short fg, const short fb,
719  const short gr, const short gg, const short gb,
720  typo s = typo::none)
721  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
722  fmt(fg,
723  const short gr, const short gg, const short gb,
724  typo s = typo::none)
725  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
726  fmt(const short fr, const short fg, const short fb,
727  bg, typo s = typo::none)
728  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
729  fmt(const short fr, const short fg, const short fb,
730  typo s = typo::none)
731  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
732 
733  fmt(const std::string& f, const std::string& b, typo s = typo::none)
734  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
735  fmt(fg, const std::string& b, typo s = typo::none)
736  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
737  fmt(const std::string& f, bg, typo s = typo::none)
738  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
739  fmt(const std::string& f, typo s = typo::none)
740  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
743  protected:
744 
746  std::ostream& print_on( std::ostream& os) const
747  {
748  if(mode == ansi::colors_16) {
749  // Print all in a single escape.
750  os << std::make_tuple(fore,back,style);
751 
752  } else {
753  // 256 or 16M: always print separated escapes for foreground/background.
754  if(mode == ansi::colors_256) {
755  os << fore_256;
756  os << back_256;
757 
758  } else if(mode == ansi::colors_16M) {
759  os << fore_16M;
760  os << back_16M;
761  }
762  // In any case, print the style separately.
763  os << style;
764  }
765  return os;
766  }
767 
768  public:
780  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
781  {
782  return fmt.print_on(os);
783  }
784 
795  std::string operator()( const std::string& msg ) const
796  {
797  std::ostringstream os;
798  this->print_on(os);
799  fmt reset(fmt::typo::reset);
800  os << msg;
801  reset.print_on(os);
802  return os.str();
803  }
804 
807  std::string str() const
808  {
809  std::ostringstream os;
810  this->print_on(os);
811  return os.str();
812  }
813  }; // fmt class
814 
820  public:
821  clutchlog(clutchlog const&) = delete;
822  void operator=(clutchlog const&) = delete;
823 
824  private:
825  clutchlog() :
826  // system, main, log
828  _level_word({
829  {level::critical,"Critical"},
830  {level::error ,"Error"},
831  {level::warning ,"Warning"},
832  {level::progress,"Progress"},
833  {level::note ,"Note"},
834  {level::info ,"Info"},
835  {level::debug ,"Debug"},
836  {level::xdebug ,"XDebug"}
837  }),
838  _level_short({
839  {level::critical, "Crit"},
840  {level::error , "Erro"},
841  {level::warning , "Warn"},
842  {level::progress, "Prog"},
843  {level::note , "Note"},
844  {level::info , "Info"},
845  {level::debug , "Dbug"},
846  {level::xdebug , "XDbg"}
847  }),
848  _level_fmt({
849  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
850  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
851  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
852  {level::progress,fmt()},
853  {level::note ,fmt()},
854  {level::info ,fmt()},
855  {level::debug ,fmt()},
856  {level::xdebug ,fmt()}
857  }),
860  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
861  _hfill_char(clutchlog::default_hfill_char),
862  _hfill_fmt(fmt::fg::none),
863  _hfill_max(clutchlog::default_hfill_max),
864  _hfill_min(clutchlog::default_hfill_min),
865  #endif
866  _out(&std::clog),
867  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
868  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
869  _depth_mark(clutchlog::default_depth_mark),
870  #endif
871  _stage(level::error),
872  _in_file(".*"),
873  _in_func(".*"),
874  _in_line(".*")
875  {
876  // Reverse the level->word map into a word->level map.
877  for(auto& lw : _level_word) {
878  _word_level[lw.second] = lw.first;
879  }
880 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
881  struct winsize w;
882  ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
883  _nb_columns = std::max(std::min((size_t)w.ws_col, default_hfill_max), default_hfill_min);
884 #endif
885  }
886 
887  protected:
889  size_t _strip_calls;
891  const std::map<level,std::string> _level_word;
893  std::map<std::string,level> _word_level;
895  std::map<level,std::string> _level_short;
897  std::map<level,fmt> _level_fmt;
899  std::string _format_log;
901  std::string _format_dump;
902  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
903 
904  char _hfill_char;
906  fmt _hfill_fmt;
908  size_t _hfill_max;
910  size_t _hfill_min;
911  #endif
912 
913  std::ostream* _out;
914  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
915 
916  size_t _depth;
918  std::string _depth_mark;
919  #endif
920 
923  std::regex _in_file;
925  std::regex _in_func;
927  std::regex _in_line;
928 
929 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
930 
931  static const size_t _max_buffer = 4096;
932 #endif
933 
934 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
935 
936  size_t _nb_columns;
937 #endif
938 
940  public:
941 
945  void format(const std::string& format) {_format_log = format;}
948  std::string format() const {return _format_log;}
949 
951  void format_comment(const std::string& format) {_format_dump = format;}
953  std::string format_comment() const {return _format_dump;}
954 
956  void out(std::ostream& out) {_out = &out;}
958  std::ostream& out() {return *_out;}
959 
960 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
961  void depth(size_t d) {_depth = d;}
964  size_t depth() const {return _depth;}
965 
967  void depth_mark(const std::string mark) {_depth_mark = mark;}
969  std::string depth_mark() const {return _depth_mark;}
970 
972  void strip_calls(const size_t n) {_strip_calls = n;}
974  size_t strip_calls() const {return _strip_calls;}
975 #endif
976 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
977  void hfill_mark(const char mark) {_hfill_char = mark;}
980  char hfill_mark() const {return _hfill_char;}
982  void hfill_style(fmt style) {_hfill_fmt = style;}
987  template<class ... FMT>
988  void hfill_style(FMT... styles) { this->hfill_style(fmt(styles...)); }
990  fmt hfill_style() const {return _hfill_fmt;}
992  void hfill_max(const size_t nmax) {_hfill_max = nmax;}
994  size_t hfill_max() {return _hfill_max;}
996  void hfill_min(const size_t nmin) {_hfill_min = nmin;}
998  size_t hfill_min() {return _hfill_min;}
999 #endif
1000 
1002  void threshold(level l) {_stage = l;}
1004  void threshold(const std::string& l) {_stage = this->level_of(l);}
1006  level threshold() const {return _stage;}
1008  const std::map<std::string,level>& levels() const { return _word_level;}
1009 
1014  level level_of(const std::string name)
1015  {
1016  const auto ilevel = _word_level.find(name);
1017  if( ilevel != std::end(_word_level)) {
1018  return ilevel->second;
1019  } else {
1020  throw std::out_of_range("'" + name + "' is not a valid log level name");
1021  }
1022  }
1023 
1025  void file(std::string file) {_in_file = file;}
1027  void func(std::string func) {_in_func = func;}
1029  void line(std::string line) {_in_line = line;}
1030 
1032  void location(
1033  const std::string& in_file,
1034  const std::string& in_function=".*",
1035  const std::string& in_line=".*"
1036  )
1037  {
1038  file(in_file);
1039  func(in_function);
1040  line(in_line);
1041  }
1042 
1047  template<class ... FMT>
1048  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
1050  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
1052  fmt style(level stage) const { return _level_fmt.at(stage); }
1053 
1056  public:
1057 
1061  struct scope_t {
1064  bool matches;
1067 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1068 
1069  size_t depth;
1070 #endif
1071 
1072  bool there;
1075  matches(false),
1076  stage(level::xdebug),
1078  depth(0),
1079 #endif
1080  there(false)
1081  {}
1082  }; // scope_t
1083 
1084 
1087  const level& stage,
1088  const std::string& file,
1089  const std::string& func,
1090  const size_t line
1091  ) const
1092  {
1093  scope_t scope; // False scope by default.
1094 
1095  /***** Log level stage *****/
1096  // Test stage first, because it's fastest.
1097  scope.stage = stage;
1098  if(not (scope.stage <= _stage)) {
1099  // Bypass useless computations if no match
1100  // because of the stage.
1101  return scope;
1102  }
1103 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1104  /***** Stack depth *****/
1105  // Backtrace in second, quite fast.
1106  size_t stack_depth;
1107  void *buffer[_max_buffer];
1108  stack_depth = backtrace(buffer, _max_buffer);
1109  scope.depth = stack_depth;
1110  if(not (scope.depth <= _depth + _strip_calls)) {
1111  // Bypass if no match.
1112  return scope;
1113  }
1114 #endif
1115 
1116  /***** Location *****/
1117  // Location last, slowest.
1118  std::ostringstream sline; sline << line;
1119  scope.there =
1120  std::regex_search(file, _in_file)
1121  and std::regex_search(func, _in_func)
1122  and std::regex_search(sline.str(), _in_line);
1123 
1124  // No need to retest stage and depth, which are true here.
1125  scope.matches = scope.there;
1126 
1127  return scope;
1128  } // locate
1129 
1137  std::string replace(
1138  const std::string& form,
1139  const std::string& mark,
1140  const std::string& tag
1141  ) const
1142  {
1143  // Useless debug code, unless something fancy would be done with name tags.
1144  // std::regex re;
1145  // try {
1146  // re = std::regex(mark);
1147  //
1148  // } catch(const std::regex_error& e) {
1149  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
1150  // switch(e.code()) {
1151  // case std::regex_constants::error_collate:
1152  // std::cerr << "the expression contains an invalid collating element name";
1153  // break;
1154  // case std::regex_constants::error_ctype:
1155  // std::cerr << "the expression contains an invalid character class name";
1156  // break;
1157  // case std::regex_constants::error_escape:
1158  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
1159  // break;
1160  // case std::regex_constants::error_backref:
1161  // std::cerr << "the expression contains an invalid back reference";
1162  // break;
1163  // case std::regex_constants::error_brack:
1164  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
1165  // break;
1166  // case std::regex_constants::error_paren:
1167  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
1168  // break;
1169  // case std::regex_constants::error_brace:
1170  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
1171  // break;
1172  // case std::regex_constants::error_badbrace:
1173  // std::cerr << "the expression contains an invalid range in a {} expression";
1174  // break;
1175  // case std::regex_constants::error_range:
1176  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
1177  // break;
1178  // case std::regex_constants::error_space:
1179  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
1180  // break;
1181  // case std::regex_constants::error_badrepeat:
1182  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
1183  // break;
1184  // case std::regex_constants::error_complexity:
1185  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
1186  // break;
1187  // case std::regex_constants::error_stack:
1188  // std::cerr << "there was not enough memory to perform a match";
1189  // break;
1190  // default:
1191  // std::cerr << "unknown error";
1192  // }
1193  // std::cerr << std::endl;
1194  // throw;
1195  // } // catch
1196 
1197  const std::regex re(mark);
1198  return std::regex_replace(form, re, tag);
1199  }
1200 
1202  std::string replace(
1203  const std::string& form,
1204  const std::string& mark,
1205  const size_t tag
1206  ) const
1207  {
1208  std::ostringstream stag; stag << tag;
1209  return replace(form, mark, stag.str());
1210  }
1211 
1213  std::string format(
1214  std::string row,
1215  const std::string& what,
1217  const std::string& name,
1218 #endif
1219  const level& stage,
1220  const std::string& file,
1221  const std::string& func,
1222  const size_t line
1224  ,
1225  const size_t depth
1226 #endif
1227  ) const
1228  {
1229  row = replace(row, "\\{msg\\}", what);
1230  row = replace(row, "\\{file\\}", file);
1231  row = replace(row, "\\{func\\}", func);
1232  row = replace(row, "\\{line\\}", line);
1233 
1234  row = replace(row, "\\{level\\}", _level_word.at(stage));
1235  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
1236  row = replace(row, "\\{level_letter\\}", letter);
1237 
1238  row = replace(row, "\\{level_short\\}", _level_short.at(stage));
1239 
1240 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1241  row = replace(row, "\\{name\\}", name);
1242  row = replace(row, "\\{depth\\}", depth - _strip_calls);
1243 
1244  std::ostringstream chevrons;
1245  for(size_t i = _strip_calls; i < depth; ++i) {
1246  chevrons << _depth_mark;
1247  }
1248  row = replace(row, "\\{depth_marks\\}", chevrons.str());
1249 #endif
1250 
1251  row = replace(row, "\\{level_fmt\\}", _level_fmt.at(stage).str());
1252 
1253 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
1254  // hfill is replaced last to allow for correct line width estimation.
1255  const std::string raw_row = replace(row, "\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]", "");
1256  const std::string hfill_tag = "{hfill}";
1257  const size_t hfill_pos = row.find(hfill_tag);
1258  const size_t raw_hfill_pos = raw_row.find(hfill_tag);
1259  const size_t nb_columns = std::max(std::min((size_t)_nb_columns, _hfill_max), _hfill_min);
1260  if(hfill_pos != std::string::npos) {
1261  assert(raw_hfill_pos != std::string::npos);
1262  if(nb_columns > 0) {
1263  const size_t left_len = raw_hfill_pos;
1264  const size_t right_len = raw_row.size() - raw_hfill_pos - hfill_tag.size();
1265  if(right_len+left_len > nb_columns) {
1266  // The right part would go over the terminal width: add a new row.
1267  if(right_len < nb_columns) {
1268  // There is room for the right part on a new line.
1269  const std::string hfill(std::max((size_t)0, nb_columns-right_len), _hfill_char);
1270  const std::string hfill_styled = _hfill_fmt(hfill);
1271  row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
1272  } else {
1273  // Right part still goes over columns: let it go.
1274  const std::string hfill(1, _hfill_char);
1275  const std::string hfill_styled = _hfill_fmt(hfill);
1276  row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
1277  }
1278  } else {
1279  // There is some space in between left and right parts.
1280  const std::string hfill(std::max((size_t)0, nb_columns - (right_len+left_len)), _hfill_char);
1281  const std::string hfill_styled = _hfill_fmt(hfill);
1282  row = replace(row, "\\{hfill\\}", hfill_styled);
1283  }
1284  } else {
1285  // We don't know the terminal width.
1286  const std::string hfill(1, _hfill_char);
1287  const std::string hfill_styled = _hfill_fmt(hfill);
1288  row = replace(row, "\\{hfill\\}", hfill_styled);
1289  }
1290  }
1291 #else
1292  // We cannot know the terminal width.
1293  const std::string hfill(1, _hfill_char);
1294  const std::string hfill_styled = _hfill_fmt(hfill);
1295  row = replace(row, "\\{hfill\\}", hfill_styled);
1296 #endif
1297  return _level_fmt.at(stage)(row);
1298  }
1299 
1301  void log(
1302  const level& stage,
1303  const std::string& what,
1304  const std::string& file, const std::string& func, size_t line
1305  ) const
1306  {
1307  scope_t scope = locate(stage, file, func, line);
1308 
1309  if(scope.matches) {
1310 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1311  *_out << format(_format_log, what, basename(getenv("_")),
1312  stage, file, func,
1313  line, scope.depth );
1314 #else
1315  *_out << format(_format_log, what,
1316  stage, file, func,
1317  line );
1318 
1319 #endif
1320  _out->flush();
1321  } // if scopes.matches
1322  }
1323 
1325  template<class In>
1326  void dump(
1327  const level& stage,
1328  const In container_begin, const In container_end,
1329  const std::string& file, const std::string& func, size_t line,
1330  const std::string& filename_template = "dump_{n}.dat",
1331  const std::string sep = dump_default_sep
1332  ) const
1333  {
1334  scope_t scope = locate(stage, file, func, line);
1335 
1336  if(scope.matches) {
1337  const std::string tag = "\\{n\\}";
1338  const std::regex re(tag);
1339  std::string outfile = "";
1340 
1341  // If the file name template has the {n} tag.
1342  if(std::regex_search(filename_template, re)) {
1343  // Increment n until a free one is found.
1344  size_t n = 0;
1345  do {
1346  outfile = replace(filename_template, tag, n);
1347  n++;
1348  } while( fs::exists( outfile ) );
1349 
1350  } else {
1351  // Use the parameter as is.
1352  outfile = filename_template;
1353  }
1354 
1355  std::ofstream fd(outfile);
1356 
1357  if(_format_dump.size() > 0) {
1358 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1359  fd << format(_format_dump, "", basename(getenv("_")),
1360  stage, file, func,
1361  line, scope.depth );
1362 #else
1363  fd << format(_format_dump, "",
1364  stage, file, func,
1365  line );
1366 #endif
1367  fd << sep; // sep after comment line.
1368  }
1369 
1370  std::copy(container_begin, container_end,
1371  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
1372 
1373  fd.close();
1374  } // if scopes.matches
1375  }
1376 
1378 };
1379 
1382 #else // not WITH_CLUTCHLOG
1383 
1384 
1385 /**********************************************************************
1386  * Fake implementation
1387  **********************************************************************/
1388 
1389 // Equivalent class with empty methods, will be optimized out
1390 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
1391 #pragma GCC diagnostic push
1392 #pragma GCC diagnostic ignored "-Wreturn-type"
1393 class clutchlog
1394 {
1395  public:
1396  static clutchlog& logger() {}
1397  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
1398  class fmt {
1399  public:
1400  enum class ansi { colors_16, colors_256, colors_16M} mode;
1401  enum class typo { reset, bold, underline, inverse, none} style;
1402  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none} fore;
1403  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none } back;
1404  protected:
1405  friend std::ostream& operator<<(std::ostream&, const std::tuple<fg,bg,typo>&) {}
1406  friend std::ostream& operator<<(std::ostream&, const typo&) {}
1407  protected:
1408  struct color {
1409  ansi mode;
1410  enum class ground { fore, back } type;
1411  color(ansi a, ground g) : mode(a), type(g) {}
1412  virtual bool is_set() const = 0;
1413  virtual std::ostream& print_on( std::ostream&) const = 0;
1414  friend std::ostream& operator<<(std::ostream&, const color&) {}
1415  };
1416  struct color_256 : public color {
1417  short index;
1418  color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
1419  color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {}
1420  bool is_set() const {}
1421  std::ostream& print_on( std::ostream&) const {}
1422  };
1423  struct fg_256 : public color_256 {
1424  fg_256() : color_256(ground::fore) {}
1425  fg_256(const short f) : color_256(ground::fore, f) {}
1426  fg_256(const fg&) : color_256(ground::fore, -1) {}
1427  } fore_256;
1428  struct bg_256 : public color_256 {
1429  bg_256() : color_256(ground::back) {}
1430  bg_256(const short b) : color_256(ground::back, b) {}
1431  bg_256(const bg&) : color_256(ground::back, -1) {}
1432  } back_256;
1433  struct color_16M : public color {
1434  short red, green, blue;
1435  color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
1436  color_16M(ground t, short r, short g, short b) : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
1437  color_16M(ground t, const std::string&) : color(ansi::colors_16M, t) {}
1438  bool is_set() const {return red > -1 and green > -1 and blue > -1;}
1439  std::ostream& print_on( std::ostream&) const {}
1440  };
1441  struct fg_16M : public color_16M {
1442  fg_16M() : color_16M(ground::fore) {}
1443  fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
1444  fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
1445  fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
1446  } fore_16M;
1447  struct bg_16M : public color_16M {
1448  bg_16M() : color_16M(ground::back) {}
1449  bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
1450  bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
1451  bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
1452  } back_16M;
1453  public:
1454  fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
1455  fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1456  fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1457  fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1458  fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1459  fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1460  fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1461  fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
1462  fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
1463  fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
1464  fmt(const short fr, const short fg, const short fb,
1465  const short gr, const short gg, const short gb,
1466  typo s = typo::none)
1467  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
1468  fmt(fg,
1469  const short gr, const short gg, const short gb,
1470  typo s = typo::none)
1471  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
1472  fmt(const short fr, const short fg, const short fb,
1473  bg, typo s = typo::none)
1474  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
1475  fmt(const short fr, const short fg, const short fb,
1476  typo s = typo::none)
1477  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
1478 
1479  fmt(const std::string& f, const std::string& b, typo s = typo::none)
1480  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
1481  fmt(fg, const std::string& b, typo s = typo::none)
1482  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
1483  fmt(const std::string& f, bg, typo s = typo::none)
1484  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
1485  fmt(const std::string& f, typo s = typo::none)
1486  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
1487  protected:
1488  std::ostream& print_on( std::ostream&) const {}
1489  public:
1490  friend std::ostream& operator<<(std::ostream&, const fmt&) {}
1491  std::string operator()( const std::string&) const {}
1492  std::string str() const {}
1493  };
1494  public:
1495  clutchlog(clutchlog const&) = delete;
1496  void operator=(clutchlog const&) = delete;
1497  private:
1498  clutchlog() {}
1499  protected:
1500  struct scope_t {};
1501  scope_t locate(
1502  const level&,
1503  const std::string&,
1504  const std::string&,
1505  const size_t
1506  ) const
1507  {}
1508  public:
1509  void format(const std::string&) {}
1510  std::string format() const {}
1511 
1512  void format_comment(const std::string&) {}
1513  std::string format_comment() const {}
1514 
1515  void out(std::ostream&) {}
1516  std::ostream& out() {}
1517 
1518 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1519  void depth(size_t) {}
1520  size_t depth() const {}
1521 
1522  void depth_mark(const std::string) {}
1523  std::string depth_mark() const {}
1524  void strip_calls(const size_t) {}
1525  size_t strip_calls() const {}
1526 #endif
1527 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
1528  void hfill_mark(const char) {}
1529  char hfill_mark() const {}
1530  void hfill_fmt(fmt) {}
1531  fmt hfill_fmt() const {}
1532  void hfill_min(const size_t) {}
1533  size_t hfill_min() {}
1534  void hfill_max(const size_t) {}
1535  size_t hfill_max() {}
1536 #endif
1537 
1538  void threshold(level) {}
1539  void threshold(const std::string&) {}
1540  level threshold() const {}
1541  const std::map<std::string,level> levels() const {}
1542  level level_of(const std::string) {}
1543 
1544  void file(std::string) {}
1545  void func(std::string) {}
1546  void line(std::string) {}
1547 
1548 #pragma GCC diagnostic push
1549 #pragma GCC diagnostic ignored "-Wunused-parameter"
1550  void location(
1551  const std::string&,
1552  const std::string& in_function=".*",
1553  const std::string& in_line=".*"
1554  )
1555  {}
1556 #pragma GCC diagnostic pop
1557  template<class ... FMT>
1558  void style(level, FMT...) {}
1559  void style(level, fmt) {}
1560  fmt style(level) const {}
1561  public:
1562  std::string replace(
1563  const std::string&,
1564  const std::string&,
1565  const std::string&
1566  ) const
1567  {}
1568 
1569  std::string replace(
1570  const std::string&,
1571  const std::string&,
1572  const size_t
1573  ) const
1574  {}
1575 
1576  std::string format(
1577  std::string,
1578  const std::string&,
1580  const std::string&,
1581 #endif
1582  const level&,
1583  const std::string&,
1584  const std::string&,
1585  const size_t
1587  ,
1588  const size_t
1589 #endif
1590  ) const
1591  {}
1592 
1593  void log(
1594  const level&,
1595  const std::string&,
1596  const std::string&, const std::string&, size_t
1597  ) const
1598  {}
1599 
1600  template<class In>
1601  void dump(
1602  const level&,
1603  const In, const In,
1604  const std::string&, const std::string&, size_t,
1605  const std::string&,
1606  const std::string
1607  ) const
1608  {}
1609 };
1610 #pragma GCC diagnostic pop
1611 #endif // WITH_CLUTCHLOG
1612 
1613 #endif // CLUTCHLOG_H
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const std::tuple< fg, bg, typo > &fbs)
Output stream operator for a 3-tuple of 16-colors mode tags.
Definition: clutchlog.h:433
clutchlog::default_depth_mark
static std::string default_depth_mark
Default mark for stack depth.
Definition: clutchlog.h:249
clutchlog::_format_log
std::string _format_log
Current format of the standard output.
Definition: clutchlog.h:899
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:601
clutchlog::_level_fmt
std::map< level, fmt > _level_fmt
Dictionary of level identifier to their format.
Definition: clutchlog.h:897
clutchlog::log
void log(const level &stage, const std::string &what, const std::string &file, const std::string &func, size_t line) const
Print a log message IF the location matches the given one.
Definition: clutchlog.h:1301
clutchlog::fmt::back
enum clutchlog::fmt::bg back
Background color.
clutchlog::fmt::str
std::string str() const
Return the formatting code as a string.
Definition: clutchlog.h:807
clutchlog::fmt::fg_256
Foreground in 256-colors mode.
Definition: clutchlog.h:539
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:1029
clutchlog::fmt::color::operator<<
friend std::ostream & operator<<(std::ostream &os, const color &c)
Print the actually encoded escaped color sequence on the given stream.
Definition: clutchlog.h:493
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const typo &s)
Output stream operator for a typo tag alone, in 16-colors mode.
Definition: clutchlog.h:455
clutchlog::dump_default_format
static std::string dump_default_format
Default format of the comment line in file dump.
Definition: clutchlog.h:235
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:956
clutchlog::fmt::color_16M::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:623
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:659
clutchlog::dump_default_sep
static std::string dump_default_sep
Default item separator for dump.
Definition: clutchlog.h:242
clutchlog::format
std::string format(std::string row, const std::string &what, const level &stage, const std::string &file, const std::string &func, const size_t line) const
Substitute all tags in the format string with the corresponding information and apply the style corre...
Definition: clutchlog.h:1213
clutchlog::fmt::bg_256
Background in 256-colors mode.
Definition: clutchlog.h:556
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Compile-time default mark for stack depth.
Definition: clutchlog.h:246
clutchlog::default_strip_calls
static unsigned int default_strip_calls
Number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:256
clutchlog::default_hfill_min
static size_t default_hfill_min
Default minimum width (number of characters) at which to fill for right-aligning the right part of me...
Definition: clutchlog.h:277
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const std::string &tag) const
Replace mark by tag in form.
Definition: clutchlog.h:1137
clutchlog::fmt::color_256::color_256
color_256(ground t)
Constructor.
Definition: clutchlog.h:518
clutchlog::fmt::back_16M
clutchlog::fmt::bg_16M back_16M
Current background in 16M-colors mode.
clutchlog::fmt::color
Interface class for colors representation.
Definition: clutchlog.h:470
clutchlog::fmt::ansi::colors_16
@ colors_16
16 colors mode.
clutchlog::fmt::bg_16M
background in 256-colors mode.
Definition: clutchlog.h:664
clutchlog::default_hfill_char
static char default_hfill_char
Default character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:263
clutchlog::scope_t::matches
bool matches
Everything is compatible.
Definition: clutchlog.h:1064
clutchlog::fmt::style
enum clutchlog::fmt::typo style
Typographic style.
clutchlog::fmt::color_16M
Abstract base class for 16M colors objects (24-bits ANSI).
Definition: clutchlog.h:573
clutchlog::fmt::fg_256::fg_256
fg_256(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:551
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:951
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:684
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:1025
clutchlog::locate
scope_t locate(const level &stage, const std::string &file, const std::string &func, const size_t line) const
Gather information on the current location of the call.
Definition: clutchlog.h:1086
clutchlog::fmt::fore_16M
clutchlog::fmt::fg_16M fore_16M
Current foreground in 16M-colors mode.
clutchlog::fmt::color_256
Abstract base class for 256 colors objects (8-bits ANSI).
Definition: clutchlog.h:509
clutchlog::fmt::fmt
fmt()
Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:697
clutchlog::style
void style(level stage, fmt style)
Set the style (color and typo) of the given log level, passing a fmt instance.
Definition: clutchlog.h:1050
clutchlog::threshold
void threshold(level l)
Set the log level (below which logs are not printed) with an identifier.
Definition: clutchlog.h:1002
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:1006
clutchlog::fmt::color::is_set
virtual bool is_set() const =0
Should return true if the underying representation encodes an existing color.
clutchlog::_level_short
std::map< level, std::string > _level_short
dictionary of level identifier to their 4-letters representation.
Definition: clutchlog.h:895
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:303
clutchlog::fmt::color_256::color_256
color_256(ground t, const short i)
Constructor.
Definition: clutchlog.h:525
clutchlog::fmt::color_256::print_on
std::ostream & print_on(std::ostream &os) const
Print the color index on the given stream.
Definition: clutchlog.h:531
clutchlog::fmt::color_16M::color_16M
color_16M(ground t)
Constructor.
Definition: clutchlog.h:582
clutchlog::default_hfill_max
static size_t default_hfill_max
Default maximum width (number of characters) for which to fill for right-aligning the right part of m...
Definition: clutchlog.h:275
clutchlog::scope_t::scope_t
scope_t()
Constructor.
Definition: clutchlog.h:1074
clutchlog::_in_func
std::regex _in_func
Current function location filter.
Definition: clutchlog.h:925
clutchlog::default_format
static std::string default_format
Default format of the messages.
Definition: clutchlog.h:213
clutchlog::fmt::bg_16M::bg_16M
bg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:676
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:296
clutchlog::fmt::fg_16M
Foreground in 256-colors mode.
Definition: clutchlog.h:634
clutchlog::dump
void dump(const level &stage, const In container_begin, const In container_end, const std::string &file, const std::string &func, size_t line, const std::string &filename_template="dump_{n}.dat", const std::string sep=dump_default_sep) const
Dump a serializable container after a comment line with log information.
Definition: clutchlog.h:1326
clutchlog::fmt::fore_256
clutchlog::fmt::fg_256 fore_256
Current foreground in 256-colors mode.
clutchlog::fmt::fore
enum clutchlog::fmt::fg fore
Foreground color.
clutchlog::fmt::color::type
enum clutchlog::fmt::color::ground type
Type of color (foreground or background).
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:366
clutchlog::fmt::color_256::index
short index
The encoded color index in 4-bits ANSI.
Definition: clutchlog.h:513
clutchlog::fmt::bg_256::bg_256
bg_256()
Empty constructor: no color.
Definition: clutchlog.h:558
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:1027
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:948
clutchlog::_in_file
std::regex _in_file
Current file location filter.
Definition: clutchlog.h:923
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:1048
clutchlog::fmt::bg_256::bg_256
bg_256(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:568
clutchlog::fmt::fg_16M::fg_16M
fg_16M()
Empty constructor: no color.
Definition: clutchlog.h:636
clutchlog::level_of
level level_of(const std::string name)
Return the log level tag corresponding to the given pre-configured name.
Definition: clutchlog.h:1014
clutchlog::_level_word
const std::map< level, std::string > _level_word
Dictionary of level identifier to their string representation.
Definition: clutchlog.h:891
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:795
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:591
clutchlog::fmt::color_16M::print_on
std::ostream & print_on(std::ostream &os) const
Print the color RGB triplet on the given stream.
Definition: clutchlog.h:626
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:411
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Compile-time default format of the messages (debug mode: with absolute location).
Definition: clutchlog.h:198
clutchlog::_in_line
std::regex _in_line
Current line location filter.
Definition: clutchlog.h:927
clutchlog::fmt::fg_256::fg_256
fg_256(const short f)
Constructor.
Definition: clutchlog.h:546
clutchlog::fmt::ansi::colors_256
@ colors_256
256 colors mode.
clutchlog::fmt::mode
enum clutchlog::fmt::ansi mode
Current ANSI color mode.
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const size_t tag) const
Replace mark by tag in form, converting tag to its string representation first.
Definition: clutchlog.h:1202
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:953
clutchlog::fmt::fg_256::fg_256
fg_256()
Empty constructor: no color.
Definition: clutchlog.h:541
clutchlog::fmt::ansi::colors_16M
@ colors_16M
16 millions ("true") colors mode.
clutchlog::_format_dump
std::string _format_dump
Current format of the file output.
Definition: clutchlog.h:901
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Compile-time default item separator for dump.
Definition: clutchlog.h:239
clutchlog::fmt::bg_256::bg_256
bg_256(const short b)
Constructor.
Definition: clutchlog.h:563
clutchlog::fmt::color::ground
ground
Codes for representing foreground or background.
Definition: clutchlog.h:474
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:1062
CLUTCHLOG_DEFAULT_HFILL_MARK
#define CLUTCHLOG_DEFAULT_HFILL_MARK
Character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:260
clutchlog::fmt::print_on
std::ostream & print_on(std::ostream &os) const
Print the currently encoded format escape code on the given output stream.
Definition: clutchlog.h:746
clutchlog::fmt::color_256::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:528
clutchlog::_out
std::ostream * _out
Standard output.
Definition: clutchlog.h:913
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:958
clutchlog::threshold
void threshold(const std::string &l)
Set the log level (below which logs are not printed) with a string.
Definition: clutchlog.h:1004
clutchlog::fmt::color::print_on
virtual std::ostream & print_on(std::ostream &os) const =0
Should print the underlying representation on the given stream.
clutchlog::levels
const std::map< std::string, level > & levels() const
Get the map of available log levels string representations toward their identifier....
Definition: clutchlog.h:1008
clutchlog::_strip_calls
size_t _strip_calls
Current number of call stack levels to remove from depth display.
Definition: clutchlog.h:889
clutchlog::scope_t::stage
level stage
Current log level.
Definition: clutchlog.h:1066
clutchlog::scope_t::there
bool there
Location is compatible.
Definition: clutchlog.h:1072
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:654
CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS
Compile-time number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:253
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:780
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:689
clutchlog::fmt::bg_16M::bg_16M
bg_16M()
Empty constructor: no color.
Definition: clutchlog.h:666
clutchlog::_word_level
std::map< std::string, level > _word_level
Dictionary of level string to their identifier.
Definition: clutchlog.h:893
clutchlog::_stage
level _stage
Current log level.
Definition: clutchlog.h:921
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:1052
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:379
clutchlog::location
void location(const std::string &in_file, const std::string &in_function=".*", const std::string &in_line=".*")
Set the regular expressions filtering the location.
Definition: clutchlog.h:1032
CLUTCHLOG_HAVE_UNIX_SYSINFO
#define CLUTCHLOG_HAVE_UNIX_SYSINFO
True if POSIX headers necessary for stack depth management are available.
Definition: clutchlog.h:33
clutchlog
The single class which holds everything.
Definition: clutchlog.h:177
clutchlog::fmt::ansi
ansi
ANSI code configuring the available number of colors.
Definition: clutchlog.h:369
clutchlog::fmt::fg_16M::fg_16M
fg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:646
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:390
clutchlog::fmt::color_16M::red
short red
The encoded RGB indices.
Definition: clutchlog.h:577
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Compile-time default format of the comment line in file dump.
Definition: clutchlog.h:221
clutchlog::fmt::color::color
color(ansi a, ground g)
Constructor.
Definition: clutchlog.h:484
clutchlog::fmt::back_256
clutchlog::fmt::bg_256 back_256
Current background in 256-colors mode.