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