1 #ifndef __CLUTCHLOG_H__ 2 #define __CLUTCHLOG_H__ 16 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>) 20 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1 22 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0 28 #ifndef WITH_CLUTCHLOG 30 #define WITH_CLUTCHLOG 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" 44 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n" 46 #endif // CLUTCHLOG_DEFAULT_FORMAT 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}" 53 #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}" 55 #endif // CLUTCHDUMP_DEFAULT_FORMAT 57 #ifndef CLUTCHDUMP_DEFAULT_SEP 58 #define CLUTCHDUMP_DEFAULT_SEP "\n" 60 #endif // CLUTCHDUMP_DEFAULT_SEP 62 #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK 63 #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">" 64 #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK 66 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG 67 #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress 68 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT 71 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__ 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); \ 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); \ 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); \ 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); \ 107 #else // not WITH_CLUTCHLOG 109 #define CLUTCHLOG( LEVEL, WHAT ) { do {} while(false); } 110 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { do {} while(false); } 111 #endif // WITH_CLUTCHLOG 117 #ifdef WITH_CLUTCHLOG 141 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
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) { }
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;}
213 assert(codes.size() > 0);
215 for(
size_t i=1; i < codes.size(); ++i) {
216 os <<
";" << codes[i];
251 std::ostringstream os;
253 fmt reset(fmt::typo::reset);
267 void operator=(
clutchlog const&) =
delete;
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"}
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()}
293 _format_log(CLUTCHLOG_DEFAULT_FORMAT),
294 _format_dump(CLUTCHDUMP_DEFAULT_FORMAT),
296 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 297 _depth(std::numeric_limits<size_t>::max() - _strip_calls),
298 _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK),
300 _stage(level::error),
306 for(
auto& lw : _level_word) {
307 _word_level[lw.second] = lw.first;
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;
319 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 321 std::string _depth_mark;
332 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 338 stage(level::xdebug),
339 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 349 const std::string&
file,
350 const std::string&
func,
359 if(not (scope.stage <= _stage)) {
365 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 368 const size_t max_buffer = 4096;
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)) {
381 std::ostringstream sline; sline <<
line;
383 std::regex_search(file, _in_file)
384 and std::regex_search(func, _in_func)
385 and std::regex_search(sline.str(), _in_line);
388 scope.matches = scope.there;
403 std::string
format()
const {
return _format_log;}
413 std::ostream&
out() {
return *_out;}
415 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 416 void depth(
size_t d) {_depth = d;}
419 size_t depth()
const {
return _depth;}
422 void depth_mark(std::string mark) {_depth_mark = mark;}
424 std::string depth_mark()
const {
return _depth_mark;}
441 const std::string& in_file,
442 const std::string& in_function=
".*",
443 const std::string& in_line=
".*" 455 template<
class ... FMT>
468 const auto ilevel = _word_level.find(name);
469 if( ilevel != std::end(_word_level)) {
470 return ilevel->second;
472 throw std::out_of_range(
"'" + name +
"' is not a valid log level name");
491 const std::string& form,
492 const std::string& mark,
493 const std::string& tag
550 const std::regex re(mark);
551 return std::regex_replace(form, re, tag);
556 const std::string& form,
557 const std::string& mark,
561 std::ostringstream stag; stag << tag;
562 return replace(form, mark, stag.str());
568 const std::string& what,
569 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
570 const std::string& name,
573 const std::string&
file,
574 const std::string&
func,
576 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
582 format =
replace(format,
"\\{msg\\}", what);
583 format =
replace(format,
"\\{file\\}", file);
584 format =
replace(format,
"\\{func\\}", func);
587 format =
replace(format,
"\\{level\\}", _level_word.at(stage));
588 std::string letter(1, _level_word.at(stage).at(0));
589 format =
replace(format,
"\\{level_letter\\}", letter);
591 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 592 format =
replace(format,
"\\{name\\}", name);
593 format =
replace(format,
"\\{depth\\}", depth);
595 std::ostringstream chevrons;
596 for(
size_t i = _strip_calls; i < depth; ++i) {
597 chevrons << _depth_mark;
599 format =
replace(format,
"\\{depth_marks\\}", chevrons.str());
602 return _level_fmt.at(stage)(
format);
608 const std::string& what,
609 const std::string&
file,
const std::string&
func,
size_t line 615 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 616 *_out <<
format(_format_log, what, basename(getenv(
"_")),
620 *_out <<
format(_format_log, what,
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
642 const std::string tag =
"\\{n\\}";
643 const std::regex re(tag);
644 std::string outfile =
"";
647 if(std::regex_search(filename_template, re)) {
651 outfile =
replace(filename_template, tag, n);
653 }
while( std::filesystem::exists( outfile ) );
657 outfile = filename_template;
660 std::ofstream fd(outfile);
662 if(_format_dump.size() > 0) {
663 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 664 fd <<
format(_format_dump,
"", basename(getenv(
"_")),
668 fd <<
format(_format_dump,
"",
675 std::copy(container_begin, container_end,
676 std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
685 #else // not WITH_CLUTCHLOG 694 #pragma GCC diagnostic push 695 #pragma GCC diagnostic ignored "-Wreturn-type" 700 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
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) { }
714 std::ostream&
print_on(std::ostream&)
const { }
716 friend std::ostream&
operator<<(std::ostream&,
const fmt&) { }
717 std::string
operator()(
const std::string&)
const { }
721 void operator=(
clutchlog const&) =
delete;
734 void format(
const std::string&) {}
735 std::string
format()
const {}
740 void out(std::ostream&) {}
741 std::ostream&
out() {}
743 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 744 void depth(
size_t) {}
745 size_t depth()
const {}
747 void depth_mark(std::string) {}
748 std::string depth_mark()
const {}
754 void file(std::string) {}
755 void func(std::string) {}
756 void line(std::string) {}
758 #pragma GCC diagnostic push 759 #pragma GCC diagnostic ignored "-Wunused-parameter" 762 const std::string& in_function=
".*",
763 const std::string& in_line=
".*" 766 #pragma GCC diagnostic pop 788 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
795 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
805 const std::string&,
const std::string&,
size_t 813 const std::string&,
const std::string&,
size_t,
819 #pragma GCC diagnostic pop 820 #endif // WITH_CLUTCHLOG 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