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