clutchlog  0.8
clutchlog.h
Go to the documentation of this file.
1 #ifndef __CLUTCHLOG_H__
2 #define __CLUTCHLOG_H__
3 #pragma once
4 
6 #include <ciso646>
7  #ifdef FSEXPERIMENTAL
8  #include <experimental/filesystem>
9  namespace fs = std::experimental::filesystem;
10 #else
11  #include <filesystem>
12  namespace fs = std::filesystem;
13 #endif
14 
15 #include <iostream>
16 #include <sstream>
17 #include <fstream>
18 #include <cassert>
19 #include <cstdlib>
20 #include <string>
21 #include <limits>
22 #include <regex>
23 #include <map>
24 
26 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
27  #include <execinfo.h> // execinfo
28  #include <stdlib.h> // getenv
29  #include <libgen.h> // basename
30  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
31 #else
32  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
33 #endif
34 
35 /**********************************************************************
36  * Enable by default in Debug builds.
37  **********************************************************************/
38 #ifndef WITH_CLUTCHLOG
39  #ifndef NDEBUG
40  #define WITH_CLUTCHLOG
42  #endif
43 #endif
44 
45 /**********************************************************************
46  * Macros definitions
47  **********************************************************************/
48 #ifdef WITH_CLUTCHLOG
49 
53 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
54  #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
56 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
57 
64 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
66 
68 #ifndef NDEBUG
69  #define CLUTCHLOG( LEVEL, WHAT ) do { \
70  auto& clutchlog__logger = clutchlog::logger(); \
71  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
72  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
73  } while(0)
74 #else // not Debug build.
75  #define CLUTCHLOG( LEVEL, WHAT ) do { \
76  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
77  auto& clutchlog__logger = clutchlog::logger(); \
78  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
79  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
80  } \
81  } while(0)
82 #endif // NDEBUG
83 
85 #ifndef NDEBUG
86  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
87  auto& clutchlog__logger = clutchlog::logger(); \
88  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
89  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
90  } while(0)
91 #else // not Debug build.
92  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
93  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
94  auto& clutchlog__logger = clutchlog::logger(); \
95  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
96  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
97  } \
98  } while(0)
99 #endif // NDEBUG
100 
102 #ifndef NDEBUG
103  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
104  auto& clutchlog__logger = clutchlog::logger(); \
105  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
106  if(clutchlog__scope.matches) { \
107  FUNC(__VA_ARGS__); \
108  } \
109  } while(0)
110 #else // not Debug build.
111  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
112  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
113  auto& clutchlog__logger = clutchlog::logger(); \
114  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
115  if(clutchlog__scope.matches) { \
116  FUNC(__VA_ARGS__); \
117  } \
118  } \
119  } while(0)
120 #endif // NDEBUG
121 
123 #ifndef NDEBUG
124  #define CLUTCHCODE( LEVEL, ... ) do { \
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  __VA_ARGS__ \
129  } \
130  } while(0)
131 #else // not Debug build.
132  #define CLUTCHCODE( LEVEL, CODE ) do { \
133  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
134  auto& clutchlog__logger = clutchlog::logger(); \
135  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
136  if(clutchlog__scope.matches) { \
137  CODE \
138  } \
139  } \
140  } while(0)
141 #endif // NDEBUG
142 
145 #else // not WITH_CLUTCHLOG
146  // Disabled macros can still be called in Release builds.
147  #define CLUTCHLOG( LEVEL, WHAT ) do {/*nothing*/} while(0)
148  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {/*nothing*/} while(0)
149  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do {/*nothing*/} while(0)
150  #define CLUTCHCODE( LEVEL, CODE ) do {/*nothing*/} while(0)
151 #endif // WITH_CLUTCHLOG
152 
153 /**********************************************************************
154  * Implementation
155  **********************************************************************/
156 
157 #ifdef WITH_CLUTCHLOG
158 
166 {
167  protected:
168 
171  #ifndef NDEBUG
172  #ifndef CLUTCHLOG_DEFAULT_FORMAT
173  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
175  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
176  #else
177  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
178  #endif
179  #endif
180  #else
181  #ifndef CLUTCHLOG_DEFAULT_FORMAT
182  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
184  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\n"
185  #else
186  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\n"
187  #endif
188  #endif
189  #endif
190  static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
192 
193  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
194  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
196  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
197  #else
198  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
199  #endif
200  #endif // CLUTCHDUMP_DEFAULT_FORMAT
201  static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
203 
204  #ifndef CLUTCHDUMP_DEFAULT_SEP
205  #define CLUTCHDUMP_DEFAULT_SEP "\n"
207  #endif // CLUTCHDUMP_DEFAULT_SEP
208  static inline std::string dump_default_sep = CLUTCHDUMP_DEFAULT_SEP;
210 
211  #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
212  #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
214  #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
215  static inline std::string default_depth_mark = CLUTCHLOG_DEFAULT_DEPTH_MARK;
217 
218  #ifndef CLUTCHLOG_STRIP_CALLS
219  #define CLUTCHLOG_STRIP_CALLS 5
221  #endif // CLUTCHLOG_STRIP_CALLS
222  static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
224  /* @} */
225 
226 
227  public:
237  static clutchlog& logger()
238  {
239  static clutchlog instance;
240  return instance;
241  }
242 
244  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
245 
258  class fmt {
259  public:
261  enum class fg {
262  black = 30,
263  red = 31,
264  green = 32,
265  yellow = 33,
266  blue = 34,
267  magenta = 35,
268  cyan = 36,
269  white = 37,
270  none
271  } fore;
272 
274  enum class bg {
275  black = 40,
276  red = 41,
277  green = 42,
278  yellow = 43,
279  blue = 44,
280  magenta = 45,
281  cyan = 46,
282  white = 47,
283  none
284  } back;
285 
287  enum class typo {
288  reset = 0,
289  bold = 1,
290  underline = 4,
291  inverse = 7,
292  none
293  } style;
294 
296  fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
297 
300  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
301  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
302  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
303  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
304  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
305  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
308  protected:
310  std::ostream& print_on( std::ostream& os) const
311  {
312  std::vector<int> codes; codes.reserve(3);
313  if(this->fore != fg::none) { codes.push_back(static_cast<int>(this->fore ));}
314  if(this->back != bg::none) { codes.push_back(static_cast<int>(this->back ));}
315  if(this->style != typo::none) { codes.push_back(static_cast<int>(this->style));}
316  if(codes.size() == 0) {return os;}
317 
318  os << "\033[";
319  assert(codes.size() > 0);
320  os << codes[0];
321  for(size_t i=1; i < codes.size(); ++i) {
322  os << ";" << codes[i];
323  }
324  os << "m";
325  return os;
326  }
327 
328  public:
340  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
341  {
342  return fmt.print_on(os);
343  }
344 
355  std::string operator()( const std::string& msg ) const
356  {
357  std::ostringstream os;
358  this->print_on(os);
359  fmt reset(fmt::typo::reset);
360  os << msg;
361  reset.print_on(os);
362  return os.str();
363  }
364  }; // fmt class
365 
372  public:
373  clutchlog(clutchlog const&) = delete;
374  void operator=(clutchlog const&) = delete;
375 
376  private:
377  clutchlog() :
378  // system, main, log
380  _level_word({
381  {level::critical,"Critical"},
382  {level::error ,"Error"},
383  {level::warning ,"Warning"},
384  {level::progress,"Progress"},
385  {level::note ,"Note"},
386  {level::info ,"Info"},
387  {level::debug ,"Debug"},
388  {level::xdebug ,"XDebug"}
389  }),
390  _level_fmt({
391  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
392  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
393  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
394  {level::progress,fmt()},
395  {level::note ,fmt()},
396  {level::info ,fmt()},
397  {level::debug ,fmt()},
398  {level::xdebug ,fmt()}
399  }),
402  _out(&std::clog),
403 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
404  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
405  _depth_mark(clutchlog::default_depth_mark),
406 #endif
407  _stage(level::error),
408  _in_file(".*"),
409  _in_func(".*"),
410  _in_line(".*")
411  {
412  // Reverse the level->word map into a word->level map.
413  for(auto& lw : _level_word) {
414  _word_level[lw.second] = lw.first;
415  }
416  }
417 
418  protected:
420  const size_t _strip_calls;
422  const std::map<level,std::string> _level_word;
424  std::map<std::string,level> _word_level;
426  std::map<level,fmt> _level_fmt;
428  std::string _format_log;
430  std::string _format_dump;
432  std::ostream* _out;
433 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
434 
435  size_t _depth;
437  std::string _depth_mark;
438 #endif
439 
442  std::regex _in_file;
444  std::regex _in_func;
446  std::regex _in_line;
447 
448 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
449 
450  static const size_t max_buffer = 4096;
451 #endif
452 
454  public:
455 
459  void format(const std::string& format) {_format_log = format;}
462  std::string format() const {return _format_log;}
463 
465  void format_comment(const std::string& format) {_format_dump = format;}
467  std::string format_comment() const {return _format_dump;}
468 
470  void out(std::ostream& out) {_out = &out;}
472  std::ostream& out() {return *_out;}
473 
474 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
475  void depth(size_t d) {_depth = d;}
478  size_t depth() const {return _depth;}
479 
481  void depth_mark(std::string mark) {_depth_mark = mark;}
483  std::string depth_mark() const {return _depth_mark;}
484 #endif
485 
487  void threshold(level l) {_stage = l;}
489  void threshold(const std::string& l) {_stage = this->level_of(l);}
491  level threshold() const {return _stage;}
493  const std::map<std::string,level>& levels() const { return _word_level;}
494 
499  level level_of(const std::string name)
500  {
501  const auto ilevel = _word_level.find(name);
502  if( ilevel != std::end(_word_level)) {
503  return ilevel->second;
504  } else {
505  throw std::out_of_range("'" + name + "' is not a valid log level name");
506  }
507  }
508 
510  void file(std::string file) {_in_file = file;}
512  void func(std::string func) {_in_func = func;}
514  void line(std::string line) {_in_line = line;}
515 
517  void location(
518  const std::string& in_file,
519  const std::string& in_function=".*",
520  const std::string& in_line=".*"
521  )
522  {
523  file(in_file);
524  func(in_function);
525  line(in_line);
526  }
527 
532  template<class ... FMT>
533  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
535  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
537  fmt style(level stage) const { return _level_fmt.at(stage); }
538 
541  public:
542 
546  struct scope_t {
549  bool matches;
552 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
553 
554  size_t depth;
555 #endif
556 
557  bool there;
560  matches(false),
561  stage(level::xdebug),
563  depth(0),
564 #endif
565  there(false)
566  {}
567  }; // scope_t
568 
569 
572  const level& stage,
573  const std::string& file,
574  const std::string& func,
575  const size_t line
576  ) const
577  {
578  scope_t scope; // False scope by default.
579 
580  /***** Log level stage *****/
581  // Test stage first, because it's fastest.
582  scope.stage = stage;
583  if(not (scope.stage <= _stage)) {
584  // Bypass useless computations if no match
585  // because of the stage.
586  return scope;
587  }
588 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
589  /***** Stack depth *****/
590  // Backtrace in second, quite fast.
591  size_t stack_depth;
592  void *buffer[max_buffer];
593  stack_depth = backtrace(buffer, max_buffer);
594  scope.depth = stack_depth;
595  if(not (scope.depth <= _depth + _strip_calls)) {
596  // Bypass if no match.
597  return scope;
598  }
599 #endif
600 
601  /***** Location *****/
602  // Location last, slowest.
603  std::ostringstream sline; sline << line;
604  scope.there =
605  std::regex_search(file, _in_file)
606  and std::regex_search(func, _in_func)
607  and std::regex_search(sline.str(), _in_line);
608 
609  // No need to retest stage and depth, which are true here.
610  scope.matches = scope.there;
611 
612  return scope;
613  } // locate
614 
622  std::string replace(
623  const std::string& form,
624  const std::string& mark,
625  const std::string& tag
626  ) const
627  {
628  // Useless debug code, unless something fancy would be done with name tags.
629  // std::regex re;
630  // try {
631  // re = std::regex(mark);
632  //
633  // } catch(const std::regex_error& e) {
634  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
635  // switch(e.code()) {
636  // case std::regex_constants::error_collate:
637  // std::cerr << "the expression contains an invalid collating element name";
638  // break;
639  // case std::regex_constants::error_ctype:
640  // std::cerr << "the expression contains an invalid character class name";
641  // break;
642  // case std::regex_constants::error_escape:
643  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
644  // break;
645  // case std::regex_constants::error_backref:
646  // std::cerr << "the expression contains an invalid back reference";
647  // break;
648  // case std::regex_constants::error_brack:
649  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
650  // break;
651  // case std::regex_constants::error_paren:
652  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
653  // break;
654  // case std::regex_constants::error_brace:
655  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
656  // break;
657  // case std::regex_constants::error_badbrace:
658  // std::cerr << "the expression contains an invalid range in a {} expression";
659  // break;
660  // case std::regex_constants::error_range:
661  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
662  // break;
663  // case std::regex_constants::error_space:
664  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
665  // break;
666  // case std::regex_constants::error_badrepeat:
667  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
668  // break;
669  // case std::regex_constants::error_complexity:
670  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
671  // break;
672  // case std::regex_constants::error_stack:
673  // std::cerr << "there was not enough memory to perform a match";
674  // break;
675  // default:
676  // std::cerr << "unknown error";
677  // }
678  // std::cerr << std::endl;
679  // throw;
680  // } // catch
681 
682  const std::regex re(mark);
683  return std::regex_replace(form, re, tag);
684  }
685 
687  std::string replace(
688  const std::string& form,
689  const std::string& mark,
690  const size_t tag
691  ) const
692  {
693  std::ostringstream stag; stag << tag;
694  return replace(form, mark, stag.str());
695  }
696 
698  std::string format(
699  std::string format,
700  const std::string& what,
702  const std::string& name,
703 #endif
704  const level& stage,
705  const std::string& file,
706  const std::string& func,
707  const size_t line
709  ,
710  const size_t depth
711 #endif
712  ) const
713  {
714  format = replace(format, "\\{msg\\}", what);
715  format = replace(format, "\\{file\\}", file);
716  format = replace(format, "\\{func\\}", func);
717  format = replace(format, "\\{line\\}", line);
718 
719  format = replace(format, "\\{level\\}", _level_word.at(stage));
720  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
721  format = replace(format, "\\{level_letter\\}", letter);
722 
723 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
724  format = replace(format, "\\{name\\}", name);
725  format = replace(format, "\\{depth\\}", depth - _strip_calls);
726 
727  std::ostringstream chevrons;
728  for(size_t i = _strip_calls; i < depth; ++i) {
729  chevrons << _depth_mark;
730  }
731  format = replace(format, "\\{depth_marks\\}", chevrons.str());
732 #endif
733 
734  return _level_fmt.at(stage)(format);
735  }
736 
738  void log(
739  const level& stage,
740  const std::string& what,
741  const std::string& file, const std::string& func, size_t line
742  ) const
743  {
744  scope_t scope = locate(stage, file, func, line);
745 
746  if(scope.matches) {
747 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
748  *_out << format(_format_log, what, basename(getenv("_")),
749  stage, file, func,
750  line, scope.depth );
751 #else
752  *_out << format(_format_log, what,
753  stage, file, func,
754  line );
755 
756 #endif
757  _out->flush();
758  } // if scopes.matches
759  }
760 
762  template<class In>
763  void dump(
764  const level& stage,
765  const In container_begin, const In container_end,
766  const std::string& file, const std::string& func, size_t line,
767  const std::string& filename_template = "dump_{n}.dat",
768  const std::string sep = dump_default_sep
769  ) const
770  {
771  scope_t scope = locate(stage, file, func, line);
772 
773  if(scope.matches) {
774  const std::string tag = "\\{n\\}";
775  const std::regex re(tag);
776  std::string outfile = "";
777 
778  // If the file name template has the {n} tag.
779  if(std::regex_search(filename_template, re)) {
780  // Increment n until a free one is found.
781  size_t n = 0;
782  do {
783  outfile = replace(filename_template, tag, n);
784  n++;
785  } while( fs::exists( outfile ) );
786 
787  } else {
788  // Use the parameter as is.
789  outfile = filename_template;
790  }
791 
792  std::ofstream fd(outfile);
793 
794  if(_format_dump.size() > 0) {
795 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
796  fd << format(_format_dump, "", basename(getenv("_")),
797  stage, file, func,
798  line, scope.depth );
799 #else
800  fd << format(_format_dump, "",
801  stage, file, func,
802  line );
803 #endif
804  fd << sep; // sep after comment line.
805  }
806 
807  std::copy(container_begin, container_end,
808  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
809 
810  fd.close();
811  } // if scopes.matches
812  }
813 
815 };
816 
819 #else // not WITH_CLUTCHLOG
820 
821 
822 /**********************************************************************
823  * Fake implementation
824  **********************************************************************/
825 
826 // Equivalent class with empty methods, will be optimized out
827 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
828 #pragma GCC diagnostic push
829 #pragma GCC diagnostic ignored "-Wreturn-type"
830 class clutchlog
831 {
832  public:
833  static clutchlog& logger() {}
834  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
835  class fmt {
836  public:
837  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
838  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
839  enum class typo { reset, bold, underline, inverse, none } style;
840  fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
841  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
842  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
843  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
844  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
845  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
846  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
847  protected:
848  std::ostream& print_on(std::ostream&) const {}
849  public:
850  friend std::ostream& operator<<(std::ostream&, const fmt&) {}
851  std::string operator()(const std::string&) const {}
852  };
853  public:
854  clutchlog(clutchlog const&) = delete;
855  void operator=(clutchlog const&) = delete;
856  private:
857  clutchlog() {}
858  protected:
859  struct scope_t {};
860  scope_t locate(
861  const level&,
862  const std::string&,
863  const std::string&,
864  const size_t
865  ) const
866  {}
867  public:
868  void format(const std::string&) {}
869  std::string format() const {}
870 
871  void format_comment(const std::string&) {}
872  std::string format_comment() const {}
873 
874  void out(std::ostream&) {}
875  std::ostream& out() {}
876 
877 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
878  void depth(size_t) {}
879  size_t depth() const {}
880 
881  void depth_mark(std::string) {}
882  std::string depth_mark() const {}
883 #endif
884 
885  void threshold(level) {}
886  void threshold(const std::string&) {}
887  level threshold() const {}
888  const std::map<std::string,level> levels() const {};
889  level level_of(const std::string) {}
890 
891  void file(std::string) {}
892  void func(std::string) {}
893  void line(std::string) {}
894 
895 #pragma GCC diagnostic push
896 #pragma GCC diagnostic ignored "-Wunused-parameter"
897  void location(
898  const std::string&,
899  const std::string& in_function=".*",
900  const std::string& in_line=".*"
901  )
902  {}
903 #pragma GCC diagnostic pop
904  void style(level, fmt) {}
905  fmt style(level) const {}
906  public:
907  std::string replace(
908  const std::string&,
909  const std::string&,
910  const std::string&
911  ) const
912  {}
913 
914  std::string replace(
915  const std::string&,
916  const std::string&,
917  const size_t
918  ) const
919  {}
920 
921  std::string format(
922  std::string,
923  const std::string&,
925  const std::string&,
926 #endif
927  const level&,
928  const std::string&,
929  const std::string&,
930  const size_t
932  ,
933  const size_t
934 #endif
935  ) const
936  {}
937 
938  void log(
939  const level&,
940  const std::string&,
941  const std::string&, const std::string&, size_t
942  ) const
943  {}
944 
945  template<class In>
946  void dump(
947  const level&,
948  const In, const In,
949  const std::string&, const std::string&, size_t,
950  const std::string&,
951  const std::string
952  ) const
953  {}
954 };
955 #pragma GCC diagnostic pop
956 #endif // WITH_CLUTCHLOG
957 
958 #endif // __CLUTCHLOG_H__
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:510
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Compile-time default format of the comment line in file dump.
Definition: clutchlog.h:198
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:261
clutchlog::dump_default_format
static std::string dump_default_format
Default format of the comment line in file dump.
Definition: clutchlog.h:202
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:493
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:470
clutchlog::fmt::fmt
fmt()
&#160;Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:296
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:237
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:514
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:465
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:287
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Compile-time default item separator for dump.
Definition: clutchlog.h:206
clutchlog::default_depth_mark
static std::string default_depth_mark
Default mark for stack depth.
Definition: clutchlog.h:216
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Compile-time default format of the messages (debug mode: with absolute location).
Definition: clutchlog.h:177
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:462
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:738
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:499
clutchlog::_format_dump
std::string _format_dump
Current format of the file output.
Definition: clutchlog.h:430
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:355
clutchlog::format
std::string format(std::string format, 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:698
clutchlog::_format_log
std::string _format_log
Current format of the standard output.
Definition: clutchlog.h:428
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:244
clutchlog::scope_t::stage
level stage
Current log level.
Definition: clutchlog.h:551
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Compile-time default mark for stack depth.
Definition: clutchlog.h:213
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:340
clutchlog::_level_fmt
std::map< level, fmt > _level_fmt
Dictionary of level identifier to their format.
Definition: clutchlog.h:426
clutchlog::_in_line
std::regex _in_line
Current line location filter.
Definition: clutchlog.h:446
clutchlog::fmt::style
enum clutchlog::fmt::typo style
Typographic style.
clutchlog::_stage
level _stage
Current log level.
Definition: clutchlog.h:440
clutchlog::_strip_calls
const size_t _strip_calls
Current number of call stack levels to remove from depth display.
Definition: clutchlog.h:420
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:467
CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS
Compile-time number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:220
clutchlog::_out
std::ostream * _out
Standard output.
Definition: clutchlog.h:432
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:512
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:517
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:763
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:687
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:258
clutchlog::_in_file
std::regex _in_file
Current file location filter.
Definition: clutchlog.h:442
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:472
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:622
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:223
clutchlog::default_format
static std::string default_format
Default format of the messages.
Definition: clutchlog.h:191
clutchlog::fmt::fore
enum clutchlog::fmt::fg fore
Foreground color.
clutchlog::threshold
void threshold(const std::string &l)
Set the log level (below which logs are not printed) with a string.
Definition: clutchlog.h:489
clutchlog::scope_t::there
bool there
Location is compatible.
Definition: clutchlog.h:557
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:547
clutchlog::_in_func
std::regex _in_func
Current function location filter.
Definition: clutchlog.h:444
clutchlog::threshold
void threshold(level l)
Set the log level (below which logs are not printed) with an identifier.
Definition: clutchlog.h:487
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:535
clutchlog::_level_word
const std::map< level, std::string > _level_word
Dictionary of level identifier to their string representation.
Definition: clutchlog.h:422
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:571
clutchlog::scope_t::matches
bool matches
Everything is compatible.
Definition: clutchlog.h:549
clutchlog::dump_default_sep
static std::string dump_default_sep
Default item separator for dump.
Definition: clutchlog.h:209
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:491
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:310
clutchlog::_word_level
std::map< std::string, level > _word_level
Dictionary of level string to their identifier.
Definition: clutchlog.h:424
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:533
clutchlog::scope_t::scope_t
scope_t()
Constructor.
Definition: clutchlog.h:559
CLUTCHLOG_HAVE_UNIX_SYSINFO
#define CLUTCHLOG_HAVE_UNIX_SYSINFO
POSIX headers necessary for stack depth management are available.
Definition: clutchlog.h:32
clutchlog
Definition: clutchlog.h:165
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:537
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:274
clutchlog::fmt::back
enum clutchlog::fmt::bg back
Background color.