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
29 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
30 #else
31 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
32 #endif
33 
34 /**********************************************************************
35  * Enable by default in Debug builds.
36  **********************************************************************/
37 #ifndef WITH_CLUTCHLOG
38 #ifndef NDEBUG
39 #define WITH_CLUTCHLOG
40 #endif
41 #endif
42 
43 /**********************************************************************
44  * Macros definitions
45  **********************************************************************/
46 #ifdef WITH_CLUTCHLOG
47 
51 #ifndef CLUTCHLOG_DEFAULT_FORMAT
52 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
54 #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
55 #else
56 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
57 #endif
58 #endif // CLUTCHLOG_DEFAULT_FORMAT
59 
60 #ifndef CLUTCHDUMP_DEFAULT_FORMAT
61 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
63 #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
64 #else
65 #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
66 #endif
67 #endif // CLUTCHDUMP_DEFAULT_FORMAT
68 
69 #ifndef CLUTCHDUMP_DEFAULT_SEP
70 #define CLUTCHDUMP_DEFAULT_SEP "\n"
72 #endif // CLUTCHDUMP_DEFAULT_SEP
73 
74 #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
75 #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
77 #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
78 
79 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
80 #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
82 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
83 
89 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
91 
93 #ifndef NDEBUG
94 #define CLUTCHLOG( LEVEL, WHAT ) { \
95  auto& logger = clutchlog::logger(); \
96  std::ostringstream msg ; msg << WHAT; \
97  logger.log(clutchlog::level::LEVEL, msg.str(), CLUTCHLOC); \
98 }
99 #else // not Debug build.
100 #define CLUTCHLOG( LEVEL, WHAT ) { \
101  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
102  auto& logger = clutchlog::logger(); \
103  std::ostringstream msg ; msg << WHAT; \
104  logger.log(clutchlog::level::LEVEL, msg.str(), CLUTCHLOC); \
105  } \
106 }
107 #endif // NDEBUG
108 
110 #ifndef NDEBUG
111 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { \
112  auto& logger = clutchlog::logger(); \
113  logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
114  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
115 }
116 #else // not Debug build.
117 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { \
118  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
119  auto& logger = clutchlog::logger(); \
120  logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
121  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
122  } \
123 }
124 #endif // NDEBUG
125 
127 #ifndef NDEBUG
128 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { \
129  auto& logger = clutchlog::logger(); \
130  clutchlog::scope_t scope = logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
131  if(scope.matches) { \
132  FUNC(__VA_ARGS__); \
133  } \
134 }
135 #else // not Debug build.
136 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { \
137  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
138  auto& logger = clutchlog::logger(); \
139  clutchlog::scope_t scope = logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
140  if(scope.matches) { \
141  FUNC(__VA_ARGS__); \
142  } \
143  } \
144 }
145 #endif // NDEBUG
146 
148 #ifndef NDEBUG
149 #define CLUTCHCODE( LEVEL, ... ) { \
150  auto& logger = clutchlog::logger(); \
151  clutchlog::scope_t scope = logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
152  if(scope.matches) { \
153  __VA_ARGS__ \
154  } \
155 }
156 #else // not Debug build.
157 #define CLUTCHCODE( LEVEL, CODE ) { \
158  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
159  auto& logger = clutchlog::logger(); \
160  clutchlog::scope_t scope = logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
161  if(scope.matches) { \
162  CODE \
163  } \
164  } \
165 }
166 #endif // NDEBUG
167 
170 #else // not WITH_CLUTCHLOG
171 // Disabled macros can still be called in Release builds.
172 #define CLUTCHLOG( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
173 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { do {/*nothing*/} while(false); }
174 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { do {/*nothing*/} while(false); }
175 #define CLUTCHCODE( LEVEL, CODE ) { do {/*nothing*/} while(false); }
176 #endif // WITH_CLUTCHLOG
177 
178 /**********************************************************************
179  * Implementation
180  **********************************************************************/
181 
182 #ifdef WITH_CLUTCHLOG
183 
191 {
192  public:
202  static clutchlog& logger()
203  {
204  static clutchlog instance;
205  return instance;
206  }
207 
209  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
210 
223  class fmt {
224  public:
226  enum class fg {
227  black = 30,
228  red = 31,
229  green = 32,
230  yellow = 33,
231  blue = 34,
232  magenta = 35,
233  cyan = 36,
234  white = 37,
235  none
236  } fore;
237 
239  enum class bg {
240  black = 40,
241  red = 41,
242  green = 42,
243  yellow = 43,
244  blue = 44,
245  magenta = 45,
246  cyan = 46,
247  white = 47,
248  none
249  } back;
250 
252  enum class typo {
253  reset = 0,
254  bold = 1,
255  underline = 4,
256  inverse = 7,
257  none
258  } style;
259 
261  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
262 
265  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
266  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
267  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
268  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
269  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
270  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
273  protected:
275  std::ostream& print_on( std::ostream& os) const
276  {
277  std::vector<int> codes; codes.reserve(3);
278  if(this->fore != fg::none) { codes.push_back(static_cast<int>(this->fore ));}
279  if(this->back != bg::none) { codes.push_back(static_cast<int>(this->back ));}
280  if(this->style != typo::none) { codes.push_back(static_cast<int>(this->style));}
281  if(codes.size() == 0) {return os;}
282 
283  os << "\033[";
284  assert(codes.size() > 0);
285  os << codes[0];
286  for(size_t i=1; i < codes.size(); ++i) {
287  os << ";" << codes[i];
288  }
289  os << "m";
290  return os;
291  }
292 
293  public:
305  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
306  {
307  return fmt.print_on(os);
308  }
309 
320  std::string operator()( const std::string& msg ) const
321  {
322  std::ostringstream os;
323  this->print_on(os);
324  fmt reset(fmt::typo::reset);
325  os << msg;
326  reset.print_on(os);
327  return os.str();
328  }
329  }; // fmt class
330 
337  public:
338  clutchlog(clutchlog const&) = delete;
339  void operator=(clutchlog const&) = delete;
340 
341  private:
342  clutchlog() :
343  // system, main, log
344  _strip_calls(5),
345  _level_word({
346  {level::critical,"Critical"},
347  {level::error ,"Error"},
348  {level::warning ,"Warning"},
349  {level::progress,"Progress"},
350  {level::note ,"Note"},
351  {level::info ,"Info"},
352  {level::debug ,"Debug"},
353  {level::xdebug ,"XDebug"}
354  }),
355  _level_fmt({
356  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
357  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
358  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
359  {level::progress,fmt()},
360  {level::note ,fmt()},
361  {level::info ,fmt()},
362  {level::debug ,fmt()},
363  {level::xdebug ,fmt()}
364  }),
365  _format_log(CLUTCHLOG_DEFAULT_FORMAT),
366  _format_dump(CLUTCHDUMP_DEFAULT_FORMAT),
367  _out(&std::clog),
368 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
369  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
370  _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK),
371 #endif
372  _stage(level::error),
373  _in_file(".*"),
374  _in_func(".*"),
375  _in_line(".*")
376  {
377  // Reverse the level->word map into a word->level map.
378  for(auto& lw : _level_word) {
379  _word_level[lw.second] = lw.first;
380  }
381  }
382 
383  protected:
384  const size_t _strip_calls;
385  const std::map<level,std::string> _level_word;
386  std::map<std::string,level> _word_level;
387  std::map<level,fmt> _level_fmt;
388  std::string _format_log;
389  std::string _format_dump;
390  std::ostream* _out;
391 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
392  size_t _depth;
393  std::string _depth_mark;
394 #endif
395  level _stage;
396  std::regex _in_file;
397  std::regex _in_func;
398  std::regex _in_line;
399 
400  static const size_t max_buffer = 4096;
403  public:
404 
408  void format(const std::string& format) {_format_log = format;}
411  std::string format() const {return _format_log;}
412 
414  void format_comment(const std::string& format) {_format_dump = format;}
416  std::string format_comment() const {return _format_dump;}
417 
419  void out(std::ostream& out) {_out = &out;}
421  std::ostream& out() {return *_out;}
422 
423 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
424  void depth(size_t d) {_depth = d;}
427  size_t depth() const {return _depth;}
428 
430  void depth_mark(std::string mark) {_depth_mark = mark;}
432  std::string depth_mark() const {return _depth_mark;}
433 #endif
434 
436  void threshold(level l) {_stage = l;}
438  level threshold() const {return _stage;}
439 
441  void file(std::string file) {_in_file = file;}
443  void func(std::string func) {_in_func = func;}
445  void line(std::string line) {_in_line = line;}
446 
448  void location(
449  const std::string& in_file,
450  const std::string& in_function=".*",
451  const std::string& in_line=".*"
452  )
453  {
454  file(in_file);
455  func(in_function);
456  line(in_line);
457  }
458 
463  template<class ... FMT>
464  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
466  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
468  fmt style(level stage) const { return _level_fmt.at(stage); }
469 
474  level level_of(const std::string name)
475  {
476  const auto ilevel = _word_level.find(name);
477  if( ilevel != std::end(_word_level)) {
478  return ilevel->second;
479  } else {
480  throw std::out_of_range("'" + name + "' is not a valid log level name");
481  }
482  }
483 
486  public:
487 
491  struct scope_t {
493  bool matches; // everything is compatible
494  level stage; // current log level
495 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
496  size_t depth; // current depth
497 #endif
498  bool there; // location is compatible
499  scope_t() :
500  matches(false),
501  stage(level::xdebug),
502 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
503  depth(0),
504 #endif
505  there(false)
506  {}
507  }; // scope_t
508 
509 
512  const level& stage,
513  const std::string& file,
514  const std::string& func,
515  const size_t line
516  ) const
517  {
518  scope_t scope; // False scope by default.
519 
520  /***** Log level stage *****/
521  // Test stage first, because it's fastest.
522  scope.stage = stage;
523  if(not (scope.stage <= _stage)) {
524  // Bypass useless computations if no match
525  // because of the stage.
526  return scope;
527  }
528 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
529  /***** Stack depth *****/
530  // Backtrace in second, quite fast.
531  size_t stack_depth;
532  void *buffer[max_buffer];
533  stack_depth = backtrace(buffer, max_buffer);
534  scope.depth = stack_depth;
535  if(not (scope.depth <= _depth + _strip_calls)) {
536  // Bypass if no match.
537  return scope;
538  }
539 #endif
540 
541  /***** Location *****/
542  // Location last, slowest.
543  std::ostringstream sline; sline << line;
544  scope.there =
545  std::regex_search(file, _in_file)
546  and std::regex_search(func, _in_func)
547  and std::regex_search(sline.str(), _in_line);
548 
549  // No need to retest stage and depth, which are true here.
550  scope.matches = scope.there;
551 
552  return scope;
553  } // locate
554 
562  std::string replace(
563  const std::string& form,
564  const std::string& mark,
565  const std::string& tag
566  ) const
567  {
568  // Useless debug code, unless something fancy would be done with name tags.
569  // std::regex re;
570  // try {
571  // re = std::regex(mark);
572  //
573  // } catch(const std::regex_error& e) {
574  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
575  // switch(e.code()) {
576  // case std::regex_constants::error_collate:
577  // std::cerr << "the expression contains an invalid collating element name";
578  // break;
579  // case std::regex_constants::error_ctype:
580  // std::cerr << "the expression contains an invalid character class name";
581  // break;
582  // case std::regex_constants::error_escape:
583  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
584  // break;
585  // case std::regex_constants::error_backref:
586  // std::cerr << "the expression contains an invalid back reference";
587  // break;
588  // case std::regex_constants::error_brack:
589  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
590  // break;
591  // case std::regex_constants::error_paren:
592  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
593  // break;
594  // case std::regex_constants::error_brace:
595  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
596  // break;
597  // case std::regex_constants::error_badbrace:
598  // std::cerr << "the expression contains an invalid range in a {} expression";
599  // break;
600  // case std::regex_constants::error_range:
601  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
602  // break;
603  // case std::regex_constants::error_space:
604  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
605  // break;
606  // case std::regex_constants::error_badrepeat:
607  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
608  // break;
609  // case std::regex_constants::error_complexity:
610  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
611  // break;
612  // case std::regex_constants::error_stack:
613  // std::cerr << "there was not enough memory to perform a match";
614  // break;
615  // default:
616  // std::cerr << "unknown error";
617  // }
618  // std::cerr << std::endl;
619  // throw;
620  // } // catch
621 
622  const std::regex re(mark);
623  return std::regex_replace(form, re, tag);
624  }
625 
627  std::string replace(
628  const std::string& form,
629  const std::string& mark,
630  const size_t tag
631  ) const
632  {
633  std::ostringstream stag; stag << tag;
634  return replace(form, mark, stag.str());
635  }
636 
638  std::string format(
639  std::string format,
640  const std::string& what,
641 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
642  const std::string& name,
643 #endif
644  const level& stage,
645  const std::string& file,
646  const std::string& func,
647  const size_t line
648 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
649  ,
650  const size_t depth
651 #endif
652  ) const
653  {
654  format = replace(format, "\\{msg\\}", what);
655  format = replace(format, "\\{file\\}", file);
656  format = replace(format, "\\{func\\}", func);
657  format = replace(format, "\\{line\\}", line);
658 
659  format = replace(format, "\\{level\\}", _level_word.at(stage));
660  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
661  format = replace(format, "\\{level_letter\\}", letter);
662 
663 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
664  format = replace(format, "\\{name\\}", name);
665  format = replace(format, "\\{depth\\}", depth - _strip_calls);
666 
667  std::ostringstream chevrons;
668  for(size_t i = _strip_calls; i < depth; ++i) {
669  chevrons << _depth_mark;
670  }
671  format = replace(format, "\\{depth_marks\\}", chevrons.str());
672 #endif
673 
674  return _level_fmt.at(stage)(format);
675  }
676 
678  void log(
679  const level& stage,
680  const std::string& what,
681  const std::string& file, const std::string& func, size_t line
682  ) const
683  {
684  scope_t scope = locate(stage, file, func, line);
685 
686  if(scope.matches) {
687 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
688  *_out << format(_format_log, what, basename(getenv("_")),
689  stage, file, func,
690  line, scope.depth );
691 #else
692  *_out << format(_format_log, what,
693  stage, file, func,
694  line );
695 
696 #endif
697  _out->flush();
698  } // if scopes.matches
699  }
700 
702  template<class In>
703  void dump(
704  const level& stage,
705  const In container_begin, const In container_end,
706  const std::string& file, const std::string& func, size_t line,
707  const std::string& filename_template="dump_{n}.dat",
708  const std::string sep=CLUTCHDUMP_DEFAULT_SEP
709  ) const
710  {
711  scope_t scope = locate(stage, file, func, line);
712 
713  if(scope.matches) {
714  const std::string tag = "\\{n\\}";
715  const std::regex re(tag);
716  std::string outfile = "";
717 
718  // If the file name template has the {n} tag.
719  if(std::regex_search(filename_template, re)) {
720  // Increment n until a free one is found.
721  size_t n = 0;
722  do {
723  outfile = replace(filename_template, tag, n);
724  n++;
725  } while( fs::exists( outfile ) );
726 
727  } else {
728  // Use the parameter as is.
729  outfile = filename_template;
730  }
731 
732  std::ofstream fd(outfile);
733 
734  if(_format_dump.size() > 0) {
735 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
736  fd << format(_format_dump, "", basename(getenv("_")),
737  stage, file, func,
738  line, scope.depth );
739 #else
740  fd << format(_format_dump, "",
741  stage, file, func,
742  line );
743 #endif
744  fd << sep; // sep after comment line.
745  }
746 
747  std::copy(container_begin, container_end,
748  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
749 
750  fd.close();
751  } // if scopes.matches
752  }
753 
755 };
756 
759 #else // not WITH_CLUTCHLOG
760 
761 
762 /**********************************************************************
763  * Fake implementation
764  **********************************************************************/
765 
766 // Equivalent class with empty methods, will be optimized out
767 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
768 #pragma GCC diagnostic push
769 #pragma GCC diagnostic ignored "-Wreturn-type"
770 class clutchlog
771 {
772  public:
773  static clutchlog& logger() { }
774  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
775  class fmt {
776  public:
777  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
778  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
779  enum class typo { reset, bold, underline, inverse, none } style;
780  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
781  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
782  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
783  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
784  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
785  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
786  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
787  protected:
788  std::ostream& print_on(std::ostream&) const { }
789  public:
790  friend std::ostream& operator<<(std::ostream&, const fmt&) { }
791  std::string operator()(const std::string&) const { }
792  };
793  public:
794  clutchlog(clutchlog const&) = delete;
795  void operator=(clutchlog const&) = delete;
796  private:
797  clutchlog() {}
798  protected:
799  struct scope_t {};
800  scope_t locate(
801  const level&,
802  const std::string&,
803  const std::string&,
804  const size_t
805  ) const
806  { }
807  public:
808  void format(const std::string&) {}
809  std::string format() const {}
810 
811  void format_comment(const std::string&) {}
812  std::string format_comment() const {}
813 
814  void out(std::ostream&) {}
815  std::ostream& out() {}
816 
817 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
818  void depth(size_t) {}
819  size_t depth() const {}
820 
821  void depth_mark(std::string) {}
822  std::string depth_mark() const {}
823 #endif
824 
825  void threshold(level) {}
826  level threshold() const {}
827 
828  void file(std::string) {}
829  void func(std::string) {}
830  void line(std::string) {}
831 
832 #pragma GCC diagnostic push
833 #pragma GCC diagnostic ignored "-Wunused-parameter"
834  void location(
835  const std::string&,
836  const std::string& in_function=".*",
837  const std::string& in_line=".*"
838  )
839  { }
840 #pragma GCC diagnostic pop
841  void style(level, fmt) { }
842  fmt style(level) const { }
843  level level_of(const std::string) { }
844  public:
845  std::string replace(
846  const std::string&,
847  const std::string&,
848  const std::string&
849  ) const
850  { }
851 
852  std::string replace(
853  const std::string&,
854  const std::string&,
855  const size_t
856  ) const
857  { }
858 
859  std::string format(
860  std::string,
861  const std::string&,
862 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
863  const std::string&,
864 #endif
865  const level&,
866  const std::string&,
867  const std::string&,
868  const size_t
869 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
870  ,
871  const size_t
872 #endif
873  ) const
874  { }
875 
876  void log(
877  const level&,
878  const std::string&,
879  const std::string&, const std::string&, size_t
880  ) const
881  { }
882 
883  template<class In>
884  void dump(
885  const level&,
886  const In, const In,
887  const std::string&, const std::string&, size_t,
888  const std::string&,
889  const std::string
890  ) const
891  { }
892 };
893 #pragma GCC diagnostic pop
894 #endif // WITH_CLUTCHLOG
895 
896 #endif // __CLUTCHLOG_H__
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:678
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Default item separator for dump.
Definition: clutchlog.h:71
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:445
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:419
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:562
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Default format of the messages.
Definition: clutchlog.h:56
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:226
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:414
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:441
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:511
clutchlog::fmt::fmt
fmt()
&#160;Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:261
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:466
clutchlog::threshold
void threshold(level l)
Set the log level below which logs are not printed.
Definition: clutchlog.h:436
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:438
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:209
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:239
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:638
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:202
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:223
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:443
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:411
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Default format of the comment line in file dump.
Definition: clutchlog.h:65
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:464
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:474
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:320
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:627
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:416
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=CLUTCHDUMP_DEFAULT_SEP) const
Dump a serializable container after a comment line with log information.
Definition: clutchlog.h:703
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:492
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:275
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:421
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Default mark for stack depth.
Definition: clutchlog.h:76
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:305
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:468
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:252
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:448
clutchlog
Definition: clutchlog.h:190