Go to the documentation of this file. 1 #ifndef __CLUTCHLOG_H__
2 #define __CLUTCHLOG_H__
8 #include <experimental/filesystem>
9 namespace fs = std::experimental::filesystem;
12 namespace fs = std::filesystem;
26 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
30 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
32 #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
38 #ifndef WITH_CLUTCHLOG
40 #define WITH_CLUTCHLOG
53 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
54 #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
56 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
64 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
69 #define CLUTCHLOG( LEVEL, WHAT ) do { \
70 auto& clutchlog__logger = clutchlog::logger(); \
71 std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
72 clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
74 #else // not Debug build.
75 #define CLUTCHLOG( LEVEL, WHAT ) do { \
76 if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
77 auto& clutchlog__logger = clutchlog::logger(); \
78 std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
79 clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
86 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
87 auto& clutchlog__logger = clutchlog::logger(); \
88 clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
89 CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
91 #else // not Debug build.
92 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
93 if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
94 auto& clutchlog__logger = clutchlog::logger(); \
95 clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
96 CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
103 #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
104 auto& clutchlog__logger = clutchlog::logger(); \
105 clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
106 if(clutchlog__scope.matches) { \
110 #else // not Debug build.
111 #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
112 if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
113 auto& clutchlog__logger = clutchlog::logger(); \
114 clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
115 if(clutchlog__scope.matches) { \
124 #define CLUTCHCODE( LEVEL, ... ) do { \
125 auto& clutchlog__logger = clutchlog::logger(); \
126 clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
127 if(clutchlog__scope.matches) { \
131 #else // not Debug build.
132 #define CLUTCHCODE( LEVEL, CODE ) do { \
133 if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
134 auto& clutchlog__logger = clutchlog::logger(); \
135 clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
136 if(clutchlog__scope.matches) { \
145 #else // not WITH_CLUTCHLOG
147 #define CLUTCHLOG( LEVEL, WHAT ) do {} while(0)
148 #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {} while(0)
149 #define CLUTCHFUNC( LEVEL, FUNC, ... ) do {} while(0)
150 #define CLUTCHCODE( LEVEL, CODE ) do {} while(0)
151 #endif // WITH_CLUTCHLOG
157 #ifdef WITH_CLUTCHLOG
172 #ifndef CLUTCHLOG_DEFAULT_FORMAT
173 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
175 #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
177 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
181 #ifndef CLUTCHLOG_DEFAULT_FORMAT
182 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
184 #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\n"
186 #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\n"
193 #ifndef CLUTCHDUMP_DEFAULT_FORMAT
194 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
196 #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
198 #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
200 #endif // CLUTCHDUMP_DEFAULT_FORMAT
204 #ifndef CLUTCHDUMP_DEFAULT_SEP
205 #define CLUTCHDUMP_DEFAULT_SEP "\n"
207 #endif // CLUTCHDUMP_DEFAULT_SEP
211 #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
212 #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
214 #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
218 #ifndef CLUTCHLOG_STRIP_CALLS
219 #define CLUTCHLOG_STRIP_CALLS 5
221 #endif // CLUTCHLOG_STRIP_CALLS
244 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
312 std::vector<int> codes; codes.reserve(3);
313 if(this->
fore != fg::none) { codes.push_back(
static_cast<int>(this->
fore ));}
314 if(this->
back != bg::none) { codes.push_back(
static_cast<int>(this->
back ));}
315 if(this->
style != typo::none) { codes.push_back(
static_cast<int>(this->
style));}
316 if(codes.size() == 0) {
return os;}
319 assert(codes.size() > 0);
321 for(
size_t i=1; i < codes.size(); ++i) {
322 os <<
";" << codes[i];
357 std::ostringstream os;
359 fmt reset(fmt::typo::reset);
374 void operator=(
clutchlog const&) =
delete;
381 {level::critical,
"Critical"},
382 {level::error ,
"Error"},
383 {level::warning ,
"Warning"},
384 {level::progress,
"Progress"},
385 {level::note ,
"Note"},
386 {level::info ,
"Info"},
387 {level::debug ,
"Debug"},
388 {level::xdebug ,
"XDebug"}
391 {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
392 {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
393 {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
394 {level::progress,fmt()},
395 {level::note ,fmt()},
396 {level::info ,fmt()},
397 {level::debug ,fmt()},
398 {level::xdebug ,fmt()}
403 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
404 _depth(std::numeric_limits<size_t>::max() -
_strip_calls),
433 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
437 std::string _depth_mark;
448 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
450 static const size_t max_buffer = 4096;
474 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
475 void depth(
size_t d) {_depth = d;}
478 size_t depth()
const {
return _depth;}
481 void depth_mark(std::string mark) {_depth_mark = mark;}
483 std::string depth_mark()
const {
return _depth_mark;}
503 return ilevel->second;
505 throw std::out_of_range(
"'" + name +
"' is not a valid log level name");
518 const std::string& in_file,
519 const std::string& in_function=
".*",
520 const std::string& in_line=
".*"
532 template<
class ... FMT>
552 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
573 const std::string&
file,
574 const std::string&
func,
583 if(not (scope.stage <=
_stage)) {
588 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
592 void *buffer[max_buffer];
593 stack_depth = backtrace(buffer, max_buffer);
594 scope.depth = stack_depth;
603 std::ostringstream sline; sline <<
line;
607 and std::regex_search(sline.str(),
_in_line);
610 scope.matches = scope.there;
623 const std::string& form,
624 const std::string& mark,
625 const std::string& tag
682 const std::regex re(mark);
683 return std::regex_replace(form, re, tag);
688 const std::string& form,
689 const std::string& mark,
693 std::ostringstream stag; stag << tag;
694 return replace(form, mark, stag.str());
700 const std::string& what,
702 const std::string& name,
705 const std::string&
file,
706 const std::string&
func,
720 std::string letter(1,
_level_word.at(stage).at(0));
723 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
727 std::ostringstream chevrons;
729 chevrons << _depth_mark;
740 const std::string& what,
741 const std::string&
file,
const std::string&
func,
size_t line
747 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
765 const In container_begin,
const In container_end,
766 const std::string&
file,
const std::string&
func,
size_t line,
767 const std::string& filename_template =
"dump_{n}.dat",
774 const std::string tag =
"\\{n\\}";
775 const std::regex re(tag);
776 std::string outfile =
"";
779 if(std::regex_search(filename_template, re)) {
783 outfile =
replace(filename_template, tag, n);
785 }
while( fs::exists( outfile ) );
789 outfile = filename_template;
792 std::ofstream fd(outfile);
795 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
807 std::copy(container_begin, container_end,
808 std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
819 #else // not WITH_CLUTCHLOG
828 #pragma GCC diagnostic push
829 #pragma GCC diagnostic ignored "-Wreturn-type"
834 enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
837 enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none }
fore;
838 enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none }
back;
839 enum class typo { reset, bold, underline, inverse, none }
style;
848 std::ostream&
print_on(std::ostream&)
const {}
850 friend std::ostream&
operator<<(std::ostream&,
const fmt&) {}
851 std::string
operator()(
const std::string&)
const {}
855 void operator=(
clutchlog const&) =
delete;
868 void format(
const std::string&) {}
869 std::string
format()
const {}
874 void out(std::ostream&) {}
875 std::ostream&
out() {}
877 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
878 void depth(
size_t) {}
879 size_t depth()
const {}
881 void depth_mark(std::string) {}
882 std::string depth_mark()
const {}
888 const std::map<std::string,level>
levels()
const {};
891 void file(std::string) {}
892 void func(std::string) {}
893 void line(std::string) {}
895 #pragma GCC diagnostic push
896 #pragma GCC diagnostic ignored "-Wunused-parameter"
899 const std::string& in_function=
".*",
900 const std::string& in_line=
".*"
903 #pragma GCC diagnostic pop
941 const std::string&,
const std::string&,
size_t
949 const std::string&,
const std::string&,
size_t,
955 #pragma GCC diagnostic pop
956 #endif // WITH_CLUTCHLOG
958 #endif // __CLUTCHLOG_H__
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:510
#define CLUTCHDUMP_DEFAULT_FORMAT
Compile-time default format of the comment line in file dump.
Definition: clutchlog.h:198
fg
Foreground color codes.
Definition: clutchlog.h:261
static std::string dump_default_format
Default format of the comment line in file dump.
Definition: clutchlog.h:202
const std::map< std::string, level > & levels() const
Get the map of available log levels string representations toward their identifier....
Definition: clutchlog.h:493
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:470
fmt()
 Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:296
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:237
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:514
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:465
typo
Typographic style codes.
Definition: clutchlog.h:287
#define CLUTCHDUMP_DEFAULT_SEP
Compile-time default item separator for dump.
Definition: clutchlog.h:206
static std::string default_depth_mark
Default mark for stack depth.
Definition: clutchlog.h:216
#define CLUTCHLOG_DEFAULT_FORMAT
Compile-time default format of the messages (debug mode: with absolute location).
Definition: clutchlog.h:177
std::string format() const
Get the template string.
Definition: clutchlog.h:462
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:738
level level_of(const std::string name)
Return the log level tag corresponding to the given pre-configured name.
Definition: clutchlog.h:499
std::string _format_dump
Current format of the file output.
Definition: clutchlog.h:430
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:355
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:698
std::string _format_log
Current format of the standard output.
Definition: clutchlog.h:428
level
Available log levels.
Definition: clutchlog.h:244
level stage
Current log level.
Definition: clutchlog.h:551
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Compile-time default mark for stack depth.
Definition: clutchlog.h:213
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:340
std::map< level, fmt > _level_fmt
Dictionary of level identifier to their format.
Definition: clutchlog.h:426
std::regex _in_line
Current line location filter.
Definition: clutchlog.h:446
enum clutchlog::fmt::typo style
Typographic style.
level _stage
Current log level.
Definition: clutchlog.h:440
const size_t _strip_calls
Current number of call stack levels to remove from depth display.
Definition: clutchlog.h:420
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:467
#define CLUTCHLOG_STRIP_CALLS
Compile-time number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:220
std::ostream * _out
Standard output.
Definition: clutchlog.h:432
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:512
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:517
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=dump_default_sep) const
Dump a serializable container after a comment line with log information.
Definition: clutchlog.h:763
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:687
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:258
std::regex _in_file
Current file location filter.
Definition: clutchlog.h:442
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:472
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:622
static unsigned int default_strip_calls
Number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:223
static std::string default_format
Default format of the messages.
Definition: clutchlog.h:191
enum clutchlog::fmt::fg fore
Foreground color.
void threshold(const std::string &l)
Set the log level (below which logs are not printed) with a string.
Definition: clutchlog.h:489
bool there
Location is compatible.
Definition: clutchlog.h:557
Structure holding a location matching.
Definition: clutchlog.h:547
std::regex _in_func
Current function location filter.
Definition: clutchlog.h:444
void threshold(level l)
Set the log level (below which logs are not printed) with an identifier.
Definition: clutchlog.h:487
void style(level stage, fmt style)
Set the style (color and typo) of the given log level, passing a fmt instance.
Definition: clutchlog.h:535
const std::map< level, std::string > _level_word
Dictionary of level identifier to their string representation.
Definition: clutchlog.h:422
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:571
bool matches
Everything is compatible.
Definition: clutchlog.h:549
static std::string dump_default_sep
Default item separator for dump.
Definition: clutchlog.h:209
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:491
std::ostream & print_on(std::ostream &os) const
Print the currently encoded format escape code on the given output stream.
Definition: clutchlog.h:310
std::map< std::string, level > _word_level
Dictionary of level string to their identifier.
Definition: clutchlog.h:424
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:533
scope_t()
Constructor.
Definition: clutchlog.h:559
#define CLUTCHLOG_HAVE_UNIX_SYSINFO
POSIX headers necessary for stack depth management are available.
Definition: clutchlog.h:32
Definition: clutchlog.h:165
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:537
bg
Background color codes.
Definition: clutchlog.h:274
enum clutchlog::fmt::bg back
Background color.