1 #ifndef __CLUTCHLOG_H__ 2 #define __CLUTCHLOG_H__ 18 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>) 22 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1 24 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0 30 #ifndef WITH_CLUTCHLOG 32 #define WITH_CLUTCHLOG 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" 49 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n" 51 #endif // CLUTCHLOG_DEFAULT_FORMAT 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}" 58 #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}" 60 #endif // CLUTCHDUMP_DEFAULT_FORMAT 62 #ifndef CLUTCHDUMP_DEFAULT_SEP 63 #define CLUTCHDUMP_DEFAULT_SEP "\n" 65 #endif // CLUTCHDUMP_DEFAULT_SEP 67 #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK 68 #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">" 69 #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK 71 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG 72 #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress 73 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT 80 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__ 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); \ 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); \ 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); \ 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); \ 119 #else // not WITH_CLUTCHLOG 121 #define CLUTCHLOG( LEVEL, WHAT ) { do {} while(false); } 122 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) { do {} while(false); } 123 #endif // WITH_CLUTCHLOG 129 #ifdef WITH_CLUTCHLOG 156 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
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) { }
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;}
231 assert(codes.size() > 0);
233 for(
size_t i=1; i < codes.size(); ++i) {
234 os <<
";" << codes[i];
269 std::ostringstream os;
271 fmt reset(fmt::typo::reset);
286 void operator=(
clutchlog const&) =
delete;
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"}
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()}
315 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 316 _depth(std::numeric_limits<size_t>::max() - _strip_calls),
317 _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK),
319 _stage(level::error),
325 for(
auto& lw : _level_word) {
326 _word_level[lw.second] = lw.first;
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;
338 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 340 std::string _depth_mark;
351 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 357 stage(level::xdebug),
358 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 368 const std::string&
file,
369 const std::string&
func,
378 if(not (scope.stage <= _stage)) {
384 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 387 const size_t max_buffer = 4096;
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)) {
400 std::ostringstream sline; sline <<
line;
402 std::regex_search(file, _in_file)
403 and std::regex_search(func, _in_func)
404 and std::regex_search(sline.str(), _in_line);
407 scope.matches = scope.there;
422 std::string
format()
const {
return _format_log;}
432 std::ostream&
out() {
return *_out;}
434 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 435 void depth(
size_t d) {_depth = d;}
438 size_t depth()
const {
return _depth;}
441 void depth_mark(std::string mark) {_depth_mark = mark;}
443 std::string depth_mark()
const {
return _depth_mark;}
460 const std::string& in_file,
461 const std::string& in_function=
".*",
462 const std::string& in_line=
".*" 474 template<
class ... FMT>
487 const auto ilevel = _word_level.find(name);
488 if( ilevel != std::end(_word_level)) {
489 return ilevel->second;
491 throw std::out_of_range(
"'" + name +
"' is not a valid log level name");
510 const std::string& form,
511 const std::string& mark,
512 const std::string& tag
569 const std::regex re(mark);
570 return std::regex_replace(form, re, tag);
575 const std::string& form,
576 const std::string& mark,
580 std::ostringstream stag; stag << tag;
581 return replace(form, mark, stag.str());
587 const std::string& what,
588 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
589 const std::string& name,
592 const std::string&
file,
593 const std::string&
func,
595 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
601 format =
replace(format,
"\\{msg\\}", what);
602 format =
replace(format,
"\\{file\\}", file);
603 format =
replace(format,
"\\{func\\}", func);
606 format =
replace(format,
"\\{level\\}", _level_word.at(stage));
607 std::string letter(1, _level_word.at(stage).at(0));
608 format =
replace(format,
"\\{level_letter\\}", letter);
610 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 611 format =
replace(format,
"\\{name\\}", name);
612 format =
replace(format,
"\\{depth\\}", depth);
614 std::ostringstream chevrons;
615 for(
size_t i = _strip_calls; i < depth; ++i) {
616 chevrons << _depth_mark;
618 format =
replace(format,
"\\{depth_marks\\}", chevrons.str());
621 return _level_fmt.at(stage)(
format);
627 const std::string& what,
628 const std::string&
file,
const std::string&
func,
size_t line 634 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 635 *_out <<
format(_format_log, what, basename(getenv(
"_")),
639 *_out <<
format(_format_log, what,
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",
661 const std::string tag =
"\\{n\\}";
662 const std::regex re(tag);
663 std::string outfile =
"";
666 if(std::regex_search(filename_template, re)) {
670 outfile =
replace(filename_template, tag, n);
672 }
while( std::filesystem::exists( outfile ) );
676 outfile = filename_template;
679 std::ofstream fd(outfile);
681 if(_format_dump.size() > 0) {
682 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 683 fd <<
format(_format_dump,
"", basename(getenv(
"_")),
687 fd <<
format(_format_dump,
"",
694 std::copy(container_begin, container_end,
695 std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
706 #else // not WITH_CLUTCHLOG 715 #pragma GCC diagnostic push 716 #pragma GCC diagnostic ignored "-Wreturn-type" 721 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
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) { }
735 std::ostream&
print_on(std::ostream&)
const { }
737 friend std::ostream&
operator<<(std::ostream&,
const fmt&) { }
738 std::string
operator()(
const std::string&)
const { }
742 void operator=(
clutchlog const&) =
delete;
755 void format(
const std::string&) {}
756 std::string
format()
const {}
761 void out(std::ostream&) {}
762 std::ostream&
out() {}
764 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 765 void depth(
size_t) {}
766 size_t depth()
const {}
768 void depth_mark(std::string) {}
769 std::string depth_mark()
const {}
775 void file(std::string) {}
776 void func(std::string) {}
777 void line(std::string) {}
779 #pragma GCC diagnostic push 780 #pragma GCC diagnostic ignored "-Wunused-parameter" 783 const std::string& in_function=
".*",
784 const std::string& in_line=
".*" 787 #pragma GCC diagnostic pop 809 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
816 #
if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
826 const std::string&,
const std::string&,
size_t 834 const std::string&,
const std::string&,
size_t,
840 #pragma GCC diagnostic pop 841 #endif // WITH_CLUTCHLOG 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