clutchlog  0.5.0
clutchlog.h
Go to the documentation of this file.
1 #ifndef __CLUTCHLOG_H__
2 #define __CLUTCHLOG_H__
3 #pragma once
4 
7 #include <filesystem>
8 #include <iostream>
9 #include <sstream>
10 #include <fstream>
11 #include <cassert>
12 #include <cstdlib>
13 #include <string>
14 #include <limits>
15 #include <regex>
16 #include <map>
17 
18 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
19 #include <execinfo.h> // execinfo
20 #include <stdlib.h> // getenv
21 #include <libgen.h> // basename
22 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
23 #else
24 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
25 #endif
26 
27 /**********************************************************************
28  * Enable by default in Debug builds.
29  **********************************************************************/
30 #ifndef WITH_CLUTCHLOG
31 #ifndef NDEBUG
32 #define WITH_CLUTCHLOG
33 #endif
34 #endif
35 
36 /**********************************************************************
37  * Macros definitions
38  **********************************************************************/
39 #ifdef WITH_CLUTCHLOG
40 
44 #ifndef CLUTCHLOG_DEFAULT_FORMAT
45 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
47 #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
48 #else
49 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
50 #endif
51 #endif // CLUTCHLOG_DEFAULT_FORMAT
52 
53 #ifndef CLUTCHDUMP_DEFAULT_FORMAT
54 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
56 #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
57 #else
58 #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
59 #endif
60 #endif // CLUTCHDUMP_DEFAULT_FORMAT
61 
62 #ifndef CLUTCHDUMP_DEFAULT_SEP
63 #define CLUTCHDUMP_DEFAULT_SEP "\n"
65 #endif // CLUTCHDUMP_DEFAULT_SEP
66 
67 #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
68 #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
70 #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
71 
72 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
73 #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
75 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
76 
82 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
84 
86 #ifndef NDEBUG
87 #define CLUTCHLOG( LEVEL, WHAT ) { \
88  auto& logger = clutchlog::logger(); \
89  std::ostringstream msg ; msg << WHAT; \
90  logger.log(clutchlog::level::LEVEL, msg.str(), CLUTCHLOC); \
91 }
92 #else // not Debug build.
93 #define CLUTCHLOG( LEVEL, WHAT ) { \
94  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
95  auto& logger = clutchlog::logger(); \
96  std::ostringstream msg ; msg << WHAT; \
97  logger.log(clutchlog::level::LEVEL, msg.str(), CLUTCHLOC); \
98  } \
99 }
100 #endif // NDEBUG
101 
103 #ifndef NDEBUG
104 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { \
105  auto& logger = clutchlog::logger(); \
106  logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
107  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
108 }
109 #else // not Debug build.
110 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { \
111  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
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 }
117 #endif // NDEBUG
118 
120 #ifndef NDEBUG
121 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { \
122  auto& logger = clutchlog::logger(); \
123  clutchlog::scope_t scope = logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
124  if(scope.matches) { \
125  FUNC(__VA_ARGS__); \
126  } \
127 }
128 #else // not Debug build.
129 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { do {/*nothing*/} while(false); }
130 #endif // NDEBUG
131 
134 #else // not WITH_CLUTCHLOG
135 // Disabled macros can still be used in Release builds.
136 #define CLUTCHLOG( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
137 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { do {/*nothing*/} while(false); }
138 #define CLUTCHFUNC( LEVEL, FUNC, ... ) { do {/*nothing*/} while(false); }
139 #endif // WITH_CLUTCHLOG
140 
141 /**********************************************************************
142  * Implementation
143  **********************************************************************/
144 
145 #ifdef WITH_CLUTCHLOG
146 
154 {
155  public:
165  static clutchlog& logger()
166  {
167  static clutchlog instance;
168  return instance;
169  }
170 
172  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
173 
186  class fmt {
187  public:
189  enum class fg {
190  black = 30,
191  red = 31,
192  green = 32,
193  yellow = 33,
194  blue = 34,
195  magenta = 35,
196  cyan = 36,
197  white = 37,
198  none
199  } fore;
200 
202  enum class bg {
203  black = 40,
204  red = 41,
205  green = 42,
206  yellow = 43,
207  blue = 44,
208  magenta = 45,
209  cyan = 46,
210  white = 47,
211  none
212  } back;
213 
215  enum class typo {
216  reset = 0,
217  bold = 1,
218  underline = 4,
219  inverse = 7,
220  none
221  } style;
222 
224  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
225 
228  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
229  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
230  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
231  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
232  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
233  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
236  protected:
238  std::ostream& print_on( std::ostream& os) const
239  {
240  std::vector<int> codes; codes.reserve(3);
241  if(this->fore != fg::none) { codes.push_back(static_cast<int>(this->fore ));}
242  if(this->back != bg::none) { codes.push_back(static_cast<int>(this->back ));}
243  if(this->style != typo::none) { codes.push_back(static_cast<int>(this->style));}
244  if(codes.size() == 0) {return os;}
245 
246  os << "\033[";
247  assert(codes.size() > 0);
248  os << codes[0];
249  for(size_t i=1; i < codes.size(); ++i) {
250  os << ";" << codes[i];
251  }
252  os << "m";
253  return os;
254  }
255 
256  public:
268  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
269  {
270  return fmt.print_on(os);
271  }
272 
283  std::string operator()( const std::string& msg ) const
284  {
285  std::ostringstream os;
286  this->print_on(os);
287  fmt reset(fmt::typo::reset);
288  os << msg;
289  reset.print_on(os);
290  return os.str();
291  }
292  }; // fmt class
293 
300  public:
301  clutchlog(clutchlog const&) = delete;
302  void operator=(clutchlog const&) = delete;
303 
304  private:
305  clutchlog() :
306  // system, main, log
307  _strip_calls(5),
308  _level_word({
309  {level::critical,"Critical"},
310  {level::error ,"Error"},
311  {level::warning ,"Warning"},
312  {level::progress,"Progress"},
313  {level::note ,"Note"},
314  {level::info ,"Info"},
315  {level::debug ,"Debug"},
316  {level::xdebug ,"XDebug"}
317  }),
318  _level_fmt({
319  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
320  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
321  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
322  {level::progress,fmt()},
323  {level::note ,fmt()},
324  {level::info ,fmt()},
325  {level::debug ,fmt()},
326  {level::xdebug ,fmt()}
327  }),
328  _format_log(CLUTCHLOG_DEFAULT_FORMAT),
329  _format_dump(CLUTCHDUMP_DEFAULT_FORMAT),
330  _out(&std::clog),
331 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
332  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
333  _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK),
334 #endif
335  _stage(level::error),
336  _in_file(".*"),
337  _in_func(".*"),
338  _in_line(".*")
339  {
340  // Reverse the level->word map into a word->level map.
341  for(auto& lw : _level_word) {
342  _word_level[lw.second] = lw.first;
343  }
344  }
345 
346  protected:
347  const size_t _strip_calls;
348  const std::map<level,std::string> _level_word;
349  std::map<std::string,level> _word_level;
350  std::map<level,fmt> _level_fmt;
351  std::string _format_log;
352  std::string _format_dump;
353  std::ostream* _out;
354 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
355  size_t _depth;
356  std::string _depth_mark;
357 #endif
358  level _stage;
359  std::regex _in_file;
360  std::regex _in_func;
361  std::regex _in_line;
362 
363  static const size_t max_buffer = 4096;
366  public:
367 
371  void format(const std::string& format) {_format_log = format;}
374  std::string format() const {return _format_log;}
375 
377  void format_comment(const std::string& format) {_format_dump = format;}
379  std::string format_comment() const {return _format_dump;}
380 
382  void out(std::ostream& out) {_out = &out;}
384  std::ostream& out() {return *_out;}
385 
386 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
387  void depth(size_t d) {_depth = d;}
390  size_t depth() const {return _depth;}
391 
393  void depth_mark(std::string mark) {_depth_mark = mark;}
395  std::string depth_mark() const {return _depth_mark;}
396 #endif
397 
399  void threshold(level l) {_stage = l;}
401  level threshold() const {return _stage;}
402 
404  void file(std::string file) {_in_file = file;}
406  void func(std::string func) {_in_func = func;}
408  void line(std::string line) {_in_line = line;}
409 
411  void location(
412  const std::string& in_file,
413  const std::string& in_function=".*",
414  const std::string& in_line=".*"
415  )
416  {
417  file(in_file);
418  func(in_function);
419  line(in_line);
420  }
421 
426  template<class ... FMT>
427  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
429  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
431  fmt style(level stage) const { return _level_fmt.at(stage); }
432 
437  level level_of(const std::string name)
438  {
439  const auto ilevel = _word_level.find(name);
440  if( ilevel != std::end(_word_level)) {
441  return ilevel->second;
442  } else {
443  throw std::out_of_range("'" + name + "' is not a valid log level name");
444  }
445  }
446 
449  public:
450 
454  struct scope_t {
456  bool matches; // everything is compatible
457  level stage; // current log level
458 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
459  size_t depth; // current depth
460 #endif
461  bool there; // location is compatible
462  scope_t() :
463  matches(false),
464  stage(level::xdebug),
465 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
466  depth(0),
467 #endif
468  there(false)
469  {}
470  }; // scope_t
471 
472 
475  const level& stage,
476  const std::string& file,
477  const std::string& func,
478  const size_t line
479  ) const
480  {
481  scope_t scope; // False scope by default.
482 
483  /***** Log level stage *****/
484  // Test stage first, because it's fastest.
485  scope.stage = stage;
486  if(not (scope.stage <= _stage)) {
487  // Bypass useless computations if no match
488  // because of the stage.
489  return scope;
490  }
491 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
492  /***** Stack depth *****/
493  // Backtrace in second, quite fast.
494  size_t stack_depth;
495  void *buffer[max_buffer];
496  stack_depth = backtrace(buffer, max_buffer);
497  scope.depth = stack_depth;
498  if(not (scope.depth <= _depth + _strip_calls)) {
499  // Bypass if no match.
500  return scope;
501  }
502 #endif
503 
504  /***** Location *****/
505  // Location last, slowest.
506  std::ostringstream sline; sline << line;
507  scope.there =
508  std::regex_search(file, _in_file)
509  and std::regex_search(func, _in_func)
510  and std::regex_search(sline.str(), _in_line);
511 
512  // No need to retest stage and depth, which are true here.
513  scope.matches = scope.there;
514 
515  return scope;
516  } // locate
517 
525  std::string replace(
526  const std::string& form,
527  const std::string& mark,
528  const std::string& tag
529  ) const
530  {
531  // Useless debug code, unless something fancy would be done with name tags.
532  // std::regex re;
533  // try {
534  // re = std::regex(mark);
535  //
536  // } catch(const std::regex_error& e) {
537  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
538  // switch(e.code()) {
539  // case std::regex_constants::error_collate:
540  // std::cerr << "the expression contains an invalid collating element name";
541  // break;
542  // case std::regex_constants::error_ctype:
543  // std::cerr << "the expression contains an invalid character class name";
544  // break;
545  // case std::regex_constants::error_escape:
546  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
547  // break;
548  // case std::regex_constants::error_backref:
549  // std::cerr << "the expression contains an invalid back reference";
550  // break;
551  // case std::regex_constants::error_brack:
552  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
553  // break;
554  // case std::regex_constants::error_paren:
555  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
556  // break;
557  // case std::regex_constants::error_brace:
558  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
559  // break;
560  // case std::regex_constants::error_badbrace:
561  // std::cerr << "the expression contains an invalid range in a {} expression";
562  // break;
563  // case std::regex_constants::error_range:
564  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
565  // break;
566  // case std::regex_constants::error_space:
567  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
568  // break;
569  // case std::regex_constants::error_badrepeat:
570  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
571  // break;
572  // case std::regex_constants::error_complexity:
573  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
574  // break;
575  // case std::regex_constants::error_stack:
576  // std::cerr << "there was not enough memory to perform a match";
577  // break;
578  // default:
579  // std::cerr << "unknown error";
580  // }
581  // std::cerr << std::endl;
582  // throw;
583  // } // catch
584 
585  const std::regex re(mark);
586  return std::regex_replace(form, re, tag);
587  }
588 
590  std::string replace(
591  const std::string& form,
592  const std::string& mark,
593  const size_t tag
594  ) const
595  {
596  std::ostringstream stag; stag << tag;
597  return replace(form, mark, stag.str());
598  }
599 
601  std::string format(
602  std::string format,
603  const std::string& what,
604 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
605  const std::string& name,
606 #endif
607  const level& stage,
608  const std::string& file,
609  const std::string& func,
610  const size_t line
611 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
612  ,
613  const size_t depth
614 #endif
615  ) const
616  {
617  format = replace(format, "\\{msg\\}", what);
618  format = replace(format, "\\{file\\}", file);
619  format = replace(format, "\\{func\\}", func);
620  format = replace(format, "\\{line\\}", line);
621 
622  format = replace(format, "\\{level\\}", _level_word.at(stage));
623  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
624  format = replace(format, "\\{level_letter\\}", letter);
625 
626 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
627  format = replace(format, "\\{name\\}", name);
628  format = replace(format, "\\{depth\\}", depth);
629 
630  std::ostringstream chevrons;
631  for(size_t i = _strip_calls; i < depth; ++i) {
632  chevrons << _depth_mark;
633  }
634  format = replace(format, "\\{depth_marks\\}", chevrons.str());
635 #endif
636 
637  return _level_fmt.at(stage)(format);
638  }
639 
641  void log(
642  const level& stage,
643  const std::string& what,
644  const std::string& file, const std::string& func, size_t line
645  ) const
646  {
647  scope_t scope = locate(stage, file, func, line);
648 
649  if(scope.matches) {
650 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
651  *_out << format(_format_log, what, basename(getenv("_")),
652  stage, file, func,
653  line, scope.depth );
654 #else
655  *_out << format(_format_log, what,
656  stage, file, func,
657  line );
658 
659 #endif
660  _out->flush();
661  } // if scopes.matches
662  }
663 
665  template<class In>
666  void dump(
667  const level& stage,
668  const In container_begin, const In container_end,
669  const std::string& file, const std::string& func, size_t line,
670  const std::string& filename_template="dump_{n}.dat",
671  const std::string sep=CLUTCHDUMP_DEFAULT_SEP
672  ) const
673  {
674  scope_t scope = locate(stage, file, func, line);
675 
676  if(scope.matches) {
677  const std::string tag = "\\{n\\}";
678  const std::regex re(tag);
679  std::string outfile = "";
680 
681  // If the file name template has the {n} tag.
682  if(std::regex_search(filename_template, re)) {
683  // Increment n until a free one is found.
684  size_t n = 0;
685  do {
686  outfile = replace(filename_template, tag, n);
687  n++;
688  } while( std::filesystem::exists( outfile ) );
689 
690  } else {
691  // Use the parameter as is.
692  outfile = filename_template;
693  }
694 
695  std::ofstream fd(outfile);
696 
697  if(_format_dump.size() > 0) {
698 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
699  fd << format(_format_dump, "", basename(getenv("_")),
700  stage, file, func,
701  line, scope.depth );
702 #else
703  fd << format(_format_dump, "",
704  stage, file, func,
705  line );
706 #endif
707  fd << sep; // sep after comment line.
708  }
709 
710  std::copy(container_begin, container_end,
711  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
712 
713  fd.close();
714  } // if scopes.matches
715  }
716 
718 };
719 
722 #else // not WITH_CLUTCHLOG
723 
724 
725 /**********************************************************************
726  * Fake implementation
727  **********************************************************************/
728 
729 // Equivalent class with empty methods, will be optimized out
730 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
731 #pragma GCC diagnostic push
732 #pragma GCC diagnostic ignored "-Wreturn-type"
733 class clutchlog
734 {
735  public:
736  static clutchlog& logger() { }
737  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
738  class fmt {
739  public:
740  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
741  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
742  enum class typo { reset, bold, underline, inverse, none } style;
743  fmt() : fore(fg::none), back(bg::none), style(typo::none) { }
744  fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
745  fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { }
746  fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { }
747  fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { }
748  fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { }
749  fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { }
750  protected:
751  std::ostream& print_on(std::ostream&) const { }
752  public:
753  friend std::ostream& operator<<(std::ostream&, const fmt&) { }
754  std::string operator()(const std::string&) const { }
755  };
756  public:
757  clutchlog(clutchlog const&) = delete;
758  void operator=(clutchlog const&) = delete;
759  private:
760  clutchlog() {}
761  protected:
762  struct scope_t {};
763  scope_t locate(
764  const level&,
765  const std::string&,
766  const std::string&,
767  const size_t
768  ) const
769  { }
770  public:
771  void format(const std::string&) {}
772  std::string format() const {}
773 
774  void format_comment(const std::string&) {}
775  std::string format_comment() const {}
776 
777  void out(std::ostream&) {}
778  std::ostream& out() {}
779 
780 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
781  void depth(size_t) {}
782  size_t depth() const {}
783 
784  void depth_mark(std::string) {}
785  std::string depth_mark() const {}
786 #endif
787 
788  void threshold(level) {}
789  level threshold() const {}
790 
791  void file(std::string) {}
792  void func(std::string) {}
793  void line(std::string) {}
794 
795 #pragma GCC diagnostic push
796 #pragma GCC diagnostic ignored "-Wunused-parameter"
797  void location(
798  const std::string&,
799  const std::string& in_function=".*",
800  const std::string& in_line=".*"
801  )
802  { }
803 #pragma GCC diagnostic pop
804  void style(level, fmt) { }
805  fmt style(level) const { }
806  level level_of(const std::string) { }
807  public:
808  std::string replace(
809  const std::string&,
810  const std::string&,
811  const std::string&
812  ) const
813  { }
814 
815  std::string replace(
816  const std::string&,
817  const std::string&,
818  const size_t
819  ) const
820  { }
821 
822  std::string format(
823  std::string,
824  const std::string&,
825 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
826  const std::string&,
827 #endif
828  const level&,
829  const std::string&,
830  const std::string&,
831  const size_t
832 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
833  ,
834  const size_t
835 #endif
836  ) const
837  { }
838 
839  void log(
840  const level&,
841  const std::string&,
842  const std::string&, const std::string&, size_t
843  ) const
844  { }
845 
846  template<class In>
847  void dump(
848  const level&,
849  const In, const In,
850  const std::string&, const std::string&, size_t,
851  const std::string&,
852  const std::string
853  ) const
854  { }
855 };
856 #pragma GCC diagnostic pop
857 #endif // WITH_CLUTCHLOG
858 
859 #endif // __CLUTCHLOG_H__
void threshold(level l)
Set the log level below which logs are not printed.
Definition: clutchlog.h:399
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:382
Definition: clutchlog.h:153
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:641
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:525
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:406
std::string format() const
Get the template string.
Definition: clutchlog.h:374
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:408
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:411
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:377
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:379
fmt()
 Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:224
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:601
Structure holding a location matching.
Definition: clutchlog.h:455
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:474
#define CLUTCHLOG_DEFAULT_FORMAT
Default format of the messages.
Definition: clutchlog.h:49
fg
Foreground color codes.
Definition: clutchlog.h:189
level
Available log levels.
Definition: clutchlog.h:172
#define CLUTCHDUMP_DEFAULT_FORMAT
Default format of the comment line in file dump.
Definition: clutchlog.h:58
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:384
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:268
level level_of(const std::string name)
Return the log level tag corresponding to the given pre-configured name.
Definition: clutchlog.h:437
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:427
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:283
void style(level stage, fmt style)
Set the style (color and typo) of the given log level, passing a fmt instance.
Definition: clutchlog.h:429
std::ostream & print_on(std::ostream &os) const
Print the currently encoded format escape code on the given output stream.
Definition: clutchlog.h:238
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:165
typo
Typographic style codes.
Definition: clutchlog.h:215
bg
Background color codes.
Definition: clutchlog.h:202
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:666
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:404
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:590
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:431
#define CLUTCHDUMP_DEFAULT_SEP
Default item separator for dump.
Definition: clutchlog.h:64
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:401
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Default mark for stack depth.
Definition: clutchlog.h:69
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:186