clutchlog  0.6.0
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 
25 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
26  #include <execinfo.h> // execinfo
27  #include <stdlib.h> // getenv
28  #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  } while(0)
119 #endif // NDEBUG
120 
122 #ifndef NDEBUG
123  #define CLUTCHCODE( LEVEL, ... ) do { \
124  auto& clutchlog__logger = clutchlog::logger(); \
125  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
126  if(clutchlog__scope.matches) { \
127  __VA_ARGS__ \
128  } \
129  } while(0)
130 #else // not Debug build.
131  #define CLUTCHCODE( LEVEL, CODE ) do { \
132  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
133  auto& clutchlog__logger = clutchlog::logger(); \
134  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
135  if(clutchlog__scope.matches) { \
136  CODE \
137  } \
138  } \
139  } while(0)
140 #endif // NDEBUG
141 
144 #else // not WITH_CLUTCHLOG
145  // Disabled macros can still be called in Release builds.
146  #define CLUTCHLOG( LEVEL, WHAT ) do {/*nothing*/} while(0)
147  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {/*nothing*/} while(0)
148  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do {/*nothing*/} while(0)
149  #define CLUTCHCODE( LEVEL, CODE ) do {/*nothing*/} while(0)
150 #endif // WITH_CLUTCHLOG
151 
152 /**********************************************************************
153  * Implementation
154  **********************************************************************/
155 
156 #ifdef WITH_CLUTCHLOG
157 
165 {
166  protected:
167 
170  #ifndef CLUTCHLOG_DEFAULT_FORMAT
171  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
173  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
174  #else
175  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
176  #endif
177  #endif // CLUTCHLOG_DEFAULT_FORMAT
178  static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
179 
180  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
181  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
183  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
184  #else
185  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
186  #endif
187  #endif // CLUTCHDUMP_DEFAULT_FORMAT
188  static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
189 
190  #ifndef CLUTCHDUMP_DEFAULT_SEP
191  #define CLUTCHDUMP_DEFAULT_SEP "\n"
193  #endif // CLUTCHDUMP_DEFAULT_SEP
194  static inline std::string dump_default_sep = CLUTCHDUMP_DEFAULT_SEP;
195 
196  #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
197  #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
199  #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
200  static inline std::string default_depth_mark = CLUTCHLOG_DEFAULT_DEPTH_MARK;
201 
202  #ifndef CLUTCHLOG_STRIP_CALLS
203  #define CLUTCHLOG_STRIP_CALLS 5
205  #endif // CLUTCHLOG_STRIP_CALLS
206  static inline unsigned int strip_calls = CLUTCHLOG_STRIP_CALLS;
207  /* @} */
208 
209 
210  public:
220  static clutchlog& logger()
221  {
222  static clutchlog instance;
223  return instance;
224  }
225 
227  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
228 
241  class fmt {
242  public:
244  enum class fg {
245  black = 30,
246  red = 31,
247  green = 32,
248  yellow = 33,
249  blue = 34,
250  magenta = 35,
251  cyan = 36,
252  white = 37,
253  none
254  } fore;
255 
257  enum class bg {
258  black = 40,
259  red = 41,
260  green = 42,
261  yellow = 43,
262  blue = 44,
263  magenta = 45,
264  cyan = 46,
265  white = 47,
266  none
267  } back;
268 
270  enum class typo {
271  reset = 0,
272  bold = 1,
273  underline = 4,
274  inverse = 7,
275  none
276  } style;
277 
279  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
280 
283  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
284  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
285  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
286  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
287  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
288  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
291  protected:
293  std::ostream& print_on( std::ostream& os) const
294  {
295  std::vector<int> codes; codes.reserve(3);
296  if(this->fore != fg::none) { codes.push_back(static_cast<int>(this->fore ));}
297  if(this->back != bg::none) { codes.push_back(static_cast<int>(this->back ));}
298  if(this->style != typo::none) { codes.push_back(static_cast<int>(this->style));}
299  if(codes.size() == 0) {return os;}
300 
301  os << "\033[";
302  assert(codes.size() > 0);
303  os << codes[0];
304  for(size_t i=1; i < codes.size(); ++i) {
305  os << ";" << codes[i];
306  }
307  os << "m";
308  return os;
309  }
310 
311  public:
323  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
324  {
325  return fmt.print_on(os);
326  }
327 
338  std::string operator()( const std::string& msg ) const
339  {
340  std::ostringstream os;
341  this->print_on(os);
342  fmt reset(fmt::typo::reset);
343  os << msg;
344  reset.print_on(os);
345  return os.str();
346  }
347  }; // fmt class
348 
355  public:
356  clutchlog(clutchlog const&) = delete;
357  void operator=(clutchlog const&) = delete;
358 
359  private:
360  clutchlog() :
361  // system, main, log
362  _strip_calls(clutchlog::strip_calls),
363  _level_word({
364  {level::critical,"Critical"},
365  {level::error ,"Error"},
366  {level::warning ,"Warning"},
367  {level::progress,"Progress"},
368  {level::note ,"Note"},
369  {level::info ,"Info"},
370  {level::debug ,"Debug"},
371  {level::xdebug ,"XDebug"}
372  }),
373  _level_fmt({
374  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
375  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
376  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
377  {level::progress,fmt()},
378  {level::note ,fmt()},
379  {level::info ,fmt()},
380  {level::debug ,fmt()},
381  {level::xdebug ,fmt()}
382  }),
383  _format_log(clutchlog::default_format),
384  _format_dump(clutchlog::dump_default_format),
385  _out(&std::clog),
386 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
387  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
388  _depth_mark(clutchlog::default_depth_mark),
389 #endif
390  _stage(level::error),
391  _in_file(".*"),
392  _in_func(".*"),
393  _in_line(".*")
394  {
395  // Reverse the level->word map into a word->level map.
396  for(auto& lw : _level_word) {
397  _word_level[lw.second] = lw.first;
398  }
399  }
400 
401  protected:
402  const size_t _strip_calls;
403  const std::map<level,std::string> _level_word;
404  std::map<std::string,level> _word_level;
405  std::map<level,fmt> _level_fmt;
406  std::string _format_log;
407  std::string _format_dump;
408  std::ostream* _out;
409 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
410  size_t _depth;
411  std::string _depth_mark;
412 #endif
413  level _stage;
414  std::regex _in_file;
415  std::regex _in_func;
416  std::regex _in_line;
417 
418  static const size_t max_buffer = 4096;
421  public:
422 
426  void format(const std::string& format) {_format_log = format;}
429  std::string format() const {return _format_log;}
430 
432  void format_comment(const std::string& format) {_format_dump = format;}
434  std::string format_comment() const {return _format_dump;}
435 
437  void out(std::ostream& out) {_out = &out;}
439  std::ostream& out() {return *_out;}
440 
441 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
442  void depth(size_t d) {_depth = d;}
445  size_t depth() const {return _depth;}
446 
448  void depth_mark(std::string mark) {_depth_mark = mark;}
450  std::string depth_mark() const {return _depth_mark;}
451 #endif
452 
454  void threshold(level l) {_stage = l;}
456  level threshold() const {return _stage;}
457 
459  void file(std::string file) {_in_file = file;}
461  void func(std::string func) {_in_func = func;}
463  void line(std::string line) {_in_line = line;}
464 
466  void location(
467  const std::string& in_file,
468  const std::string& in_function=".*",
469  const std::string& in_line=".*"
470  )
471  {
472  file(in_file);
473  func(in_function);
474  line(in_line);
475  }
476 
481  template<class ... FMT>
482  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
484  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
486  fmt style(level stage) const { return _level_fmt.at(stage); }
487 
492  level level_of(const std::string name)
493  {
494  const auto ilevel = _word_level.find(name);
495  if( ilevel != std::end(_word_level)) {
496  return ilevel->second;
497  } else {
498  throw std::out_of_range("'" + name + "' is not a valid log level name");
499  }
500  }
501 
504  public:
505 
509  struct scope_t {
511  bool matches; // everything is compatible
512  level stage; // current log level
513 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
514  size_t depth; // current depth
515 #endif
516  bool there; // location is compatible
517  scope_t() :
518  matches(false),
519  stage(level::xdebug),
520 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
521  depth(0),
522 #endif
523  there(false)
524  {}
525  }; // scope_t
526 
527 
530  const level& stage,
531  const std::string& file,
532  const std::string& func,
533  const size_t line
534  ) const
535  {
536  scope_t scope; // False scope by default.
537 
538  /***** Log level stage *****/
539  // Test stage first, because it's fastest.
540  scope.stage = stage;
541  if(not (scope.stage <= _stage)) {
542  // Bypass useless computations if no match
543  // because of the stage.
544  return scope;
545  }
546 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
547  /***** Stack depth *****/
548  // Backtrace in second, quite fast.
549  size_t stack_depth;
550  void *buffer[max_buffer];
551  stack_depth = backtrace(buffer, max_buffer);
552  scope.depth = stack_depth;
553  if(not (scope.depth <= _depth + _strip_calls)) {
554  // Bypass if no match.
555  return scope;
556  }
557 #endif
558 
559  /***** Location *****/
560  // Location last, slowest.
561  std::ostringstream sline; sline << line;
562  scope.there =
563  std::regex_search(file, _in_file)
564  and std::regex_search(func, _in_func)
565  and std::regex_search(sline.str(), _in_line);
566 
567  // No need to retest stage and depth, which are true here.
568  scope.matches = scope.there;
569 
570  return scope;
571  } // locate
572 
580  std::string replace(
581  const std::string& form,
582  const std::string& mark,
583  const std::string& tag
584  ) const
585  {
586  // Useless debug code, unless something fancy would be done with name tags.
587  // std::regex re;
588  // try {
589  // re = std::regex(mark);
590  //
591  // } catch(const std::regex_error& e) {
592  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
593  // switch(e.code()) {
594  // case std::regex_constants::error_collate:
595  // std::cerr << "the expression contains an invalid collating element name";
596  // break;
597  // case std::regex_constants::error_ctype:
598  // std::cerr << "the expression contains an invalid character class name";
599  // break;
600  // case std::regex_constants::error_escape:
601  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
602  // break;
603  // case std::regex_constants::error_backref:
604  // std::cerr << "the expression contains an invalid back reference";
605  // break;
606  // case std::regex_constants::error_brack:
607  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
608  // break;
609  // case std::regex_constants::error_paren:
610  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
611  // break;
612  // case std::regex_constants::error_brace:
613  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
614  // break;
615  // case std::regex_constants::error_badbrace:
616  // std::cerr << "the expression contains an invalid range in a {} expression";
617  // break;
618  // case std::regex_constants::error_range:
619  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
620  // break;
621  // case std::regex_constants::error_space:
622  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
623  // break;
624  // case std::regex_constants::error_badrepeat:
625  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
626  // break;
627  // case std::regex_constants::error_complexity:
628  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
629  // break;
630  // case std::regex_constants::error_stack:
631  // std::cerr << "there was not enough memory to perform a match";
632  // break;
633  // default:
634  // std::cerr << "unknown error";
635  // }
636  // std::cerr << std::endl;
637  // throw;
638  // } // catch
639 
640  const std::regex re(mark);
641  return std::regex_replace(form, re, tag);
642  }
643 
645  std::string replace(
646  const std::string& form,
647  const std::string& mark,
648  const size_t tag
649  ) const
650  {
651  std::ostringstream stag; stag << tag;
652  return replace(form, mark, stag.str());
653  }
654 
656  std::string format(
657  std::string format,
658  const std::string& what,
659 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
660  const std::string& name,
661 #endif
662  const level& stage,
663  const std::string& file,
664  const std::string& func,
665  const size_t line
666 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
667  ,
668  const size_t depth
669 #endif
670  ) const
671  {
672  format = replace(format, "\\{msg\\}", what);
673  format = replace(format, "\\{file\\}", file);
674  format = replace(format, "\\{func\\}", func);
675  format = replace(format, "\\{line\\}", line);
676 
677  format = replace(format, "\\{level\\}", _level_word.at(stage));
678  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
679  format = replace(format, "\\{level_letter\\}", letter);
680 
681 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
682  format = replace(format, "\\{name\\}", name);
683  format = replace(format, "\\{depth\\}", depth - _strip_calls);
684 
685  std::ostringstream chevrons;
686  for(size_t i = _strip_calls; i < depth; ++i) {
687  chevrons << _depth_mark;
688  }
689  format = replace(format, "\\{depth_marks\\}", chevrons.str());
690 #endif
691 
692  return _level_fmt.at(stage)(format);
693  }
694 
696  void log(
697  const level& stage,
698  const std::string& what,
699  const std::string& file, const std::string& func, size_t line
700  ) const
701  {
702  scope_t scope = locate(stage, file, func, line);
703 
704  if(scope.matches) {
705 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
706  *_out << format(_format_log, what, basename(getenv("_")),
707  stage, file, func,
708  line, scope.depth );
709 #else
710  *_out << format(_format_log, what,
711  stage, file, func,
712  line );
713 
714 #endif
715  _out->flush();
716  } // if scopes.matches
717  }
718 
720  template<class In>
721  void dump(
722  const level& stage,
723  const In container_begin, const In container_end,
724  const std::string& file, const std::string& func, size_t line,
725  const std::string& filename_template = "dump_{n}.dat",
726  const std::string sep = dump_default_sep
727  ) const
728  {
729  scope_t scope = locate(stage, file, func, line);
730 
731  if(scope.matches) {
732  const std::string tag = "\\{n\\}";
733  const std::regex re(tag);
734  std::string outfile = "";
735 
736  // If the file name template has the {n} tag.
737  if(std::regex_search(filename_template, re)) {
738  // Increment n until a free one is found.
739  size_t n = 0;
740  do {
741  outfile = replace(filename_template, tag, n);
742  n++;
743  } while( fs::exists( outfile ) );
744 
745  } else {
746  // Use the parameter as is.
747  outfile = filename_template;
748  }
749 
750  std::ofstream fd(outfile);
751 
752  if(_format_dump.size() > 0) {
753 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
754  fd << format(_format_dump, "", basename(getenv("_")),
755  stage, file, func,
756  line, scope.depth );
757 #else
758  fd << format(_format_dump, "",
759  stage, file, func,
760  line );
761 #endif
762  fd << sep; // sep after comment line.
763  }
764 
765  std::copy(container_begin, container_end,
766  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
767 
768  fd.close();
769  } // if scopes.matches
770  }
771 
773 };
774 
777 #else // not WITH_CLUTCHLOG
778 
779 
780 /**********************************************************************
781  * Fake implementation
782  **********************************************************************/
783 
784 // Equivalent class with empty methods, will be optimized out
785 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
786 #pragma GCC diagnostic push
787 #pragma GCC diagnostic ignored "-Wreturn-type"
788 class clutchlog
789 {
790  public:
791  static clutchlog& logger() { }
792  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
793  class fmt {
794  public:
795  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
796  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
797  enum class typo { reset, bold, underline, inverse, none } style;
798  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
799  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
800  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
801  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
802  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
803  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
804  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
805  protected:
806  std::ostream& print_on(std::ostream&) const { }
807  public:
808  friend std::ostream& operator<<(std::ostream&, const fmt&) { }
809  std::string operator()(const std::string&) const { }
810  };
811  public:
812  clutchlog(clutchlog const&) = delete;
813  void operator=(clutchlog const&) = delete;
814  private:
815  clutchlog() {}
816  protected:
817  struct scope_t {};
818  scope_t locate(
819  const level&,
820  const std::string&,
821  const std::string&,
822  const size_t
823  ) const
824  { }
825  public:
826  void format(const std::string&) {}
827  std::string format() const {}
828 
829  void format_comment(const std::string&) {}
830  std::string format_comment() const {}
831 
832  void out(std::ostream&) {}
833  std::ostream& out() {}
834 
835 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
836  void depth(size_t) {}
837  size_t depth() const {}
838 
839  void depth_mark(std::string) {}
840  std::string depth_mark() const {}
841 #endif
842 
843  void threshold(level) {}
844  level threshold() const {}
845 
846  void file(std::string) {}
847  void func(std::string) {}
848  void line(std::string) {}
849 
850 #pragma GCC diagnostic push
851 #pragma GCC diagnostic ignored "-Wunused-parameter"
852  void location(
853  const std::string&,
854  const std::string& in_function=".*",
855  const std::string& in_line=".*"
856  )
857  { }
858 #pragma GCC diagnostic pop
859  void style(level, fmt) { }
860  fmt style(level) const { }
861  level level_of(const std::string) { }
862  public:
863  std::string replace(
864  const std::string&,
865  const std::string&,
866  const std::string&
867  ) const
868  { }
869 
870  std::string replace(
871  const std::string&,
872  const std::string&,
873  const size_t
874  ) const
875  { }
876 
877  std::string format(
878  std::string,
879  const std::string&,
880 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
881  const std::string&,
882 #endif
883  const level&,
884  const std::string&,
885  const std::string&,
886  const size_t
887 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
888  ,
889  const size_t
890 #endif
891  ) const
892  { }
893 
894  void log(
895  const level&,
896  const std::string&,
897  const std::string&, const std::string&, size_t
898  ) const
899  { }
900 
901  template<class In>
902  void dump(
903  const level&,
904  const In, const In,
905  const std::string&, const std::string&, size_t,
906  const std::string&,
907  const std::string
908  ) const
909  { }
910 };
911 #pragma GCC diagnostic pop
912 #endif // WITH_CLUTCHLOG
913 
914 #endif // __CLUTCHLOG_H__
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:459
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Default format of the comment line in file dump.
Definition: clutchlog.h:185
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:244
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:437
clutchlog::fmt::fmt
fmt()
&#160;Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:279
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:220
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:463
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:432
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:270
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Default item separator for dump.
Definition: clutchlog.h:192
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Default format of the messages.
Definition: clutchlog.h:175
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:429
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:696
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:492
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:338
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:656
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:227
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Default mark for stack depth.
Definition: clutchlog.h:198
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:323
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:434
CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS
Number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:204
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:461
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:466
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:721
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:645
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:241
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:439
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:580
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:510
clutchlog::threshold
void threshold(level l)
Set the log level below which logs are not printed.
Definition: clutchlog.h:454
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:484
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:529
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:456
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:293
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:482
clutchlog
Definition: clutchlog.h:164
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:486
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:257