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