diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d68b58..7a910a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_STANDARD 17) ## Current version set(VERSION_MAJOR 0 CACHE STRING "Major version number" ) -set(VERSION_MINOR 2 CACHE STRING "Minor version number" ) +set(VERSION_MINOR 3 CACHE STRING "Minor version number" ) set(VERSION_PATCH 0 CACHE STRING "Patch version number" ) mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH) diff --git a/README.md b/README.md index 6556b7a..d24f045 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ Clutchlog allows to select which log messages will be displayed, based on their - *source code location*: you can ask to display messages called from given files, functions and line number, all based on regular expressions. -Of course, Clutchlog is disabled by default if not in "Debug" mode. +Additionally, Clutchlog will do its best to allow the compiler to optimize out calls, +for instance debug messages in "Release" builds. Example @@ -182,7 +183,7 @@ for log levels which are under or equal to `progress`. You can change this behavior at compile time by setting the `CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG` preprocessor variable to the desired maximum log level, for example: -``` +```cpp // Will always allow to log everything even in Release mode. #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::xdebug ``` @@ -223,8 +224,13 @@ log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), "main.cpp", "main", Limitations =========== -Because the call stack depth and binary name access are system-dependent, -Clutchlog is only implemented for Linux at the moment. +Because the call stack depth and program name access are system-dependent, +the features relying on the depth of the call stack and the display of the program name +are only available for operating systems having the following headers: +`execinfo.h`, `stdlib.h` and `libgen.h` (so far, tested with Linux). + +Clutchlog needs `C++-17` with the `filesystem` feature. +You may need to indicate `-std=c++17 -lstdc++fs` to your compiler. Build and tests @@ -235,7 +241,7 @@ and either ensure that the `NDEBUG` preprocessor variable is not set, either define the `WITH_CLUTCHLOG` preprocessor variable. If you're using CMake (or another modern build system), -it will unset `NDEBUG` ---and thus enable clutchlog--- +it will unset `NDEBUG` —and thus enable clutchlog— only for the "Debug" build type, which is usually what you want if you use clutchlog, anyway. diff --git a/clutchlog/clutchlog.h b/clutchlog/clutchlog.h index 3fae2b0..f0ccb19 100644 --- a/clutchlog/clutchlog.h +++ b/clutchlog/clutchlog.h @@ -8,17 +8,19 @@ #include #include #include -// #include #include #include #include #include -// #ifdef __unix__ -#include -#include -#include -// #endif +#if __has_include() && __has_include() && __has_include() +#include // execinfo +#include // getenv +#include // basename +#define CLUTCHLOG_HAVE_UNIX_SYSINFO 1 +#else +#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0 +#endif /********************************************************************** * Enable by default in Debug builds. @@ -36,12 +38,20 @@ #ifndef CLUTCHLOG_DEFAULT_FORMAT //! Default format of the messages. +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n" +#else +#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n" +#endif #endif // CLUTCHLOG_DEFAULT_FORMAT #ifndef CLUTCHDUMP_DEFAULT_FORMAT //! Default format of the comment line in file dump. +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}" +#else +#define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}" +#endif #endif // CLUTCHDUMP_DEFAULT_FORMAT #ifndef CLUTCHDUMP_DEFAULT_SEP @@ -150,12 +160,14 @@ class clutchlog _format_log(CLUTCHLOG_DEFAULT_FORMAT), _format_dump(CLUTCHDUMP_DEFAULT_FORMAT), _out(&std::clog), +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 _depth(std::numeric_limits::max() - _strip_calls), + _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK), +#endif _stage(level::error), _in_file(".*"), _in_func(".*"), - _in_line(".*"), - _depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK) + _in_line(".*") {} protected: @@ -164,22 +176,28 @@ class clutchlog std::string _format_log; std::string _format_dump; std::ostream* _out; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 size_t _depth; + std::string _depth_mark; +#endif level _stage; std::regex _in_file; std::regex _in_func; std::regex _in_line; - std::string _depth_mark; struct scope_t { bool matches; // everything is compatible level stage; // current log level +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 size_t depth; // current depth +#endif bool there; // location is compatible scope_t() : matches(false), stage(level::xdebug), +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 depth(0), +#endif there(false) {} }; @@ -203,6 +221,7 @@ class clutchlog return scope; } +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 /***** Stack depth *****/ // Backtrace in second, quite fast. const size_t max_buffer = 4096; @@ -214,6 +233,7 @@ class clutchlog // Bypass if no match. return scope; } +#endif /***** Location *****/ // Location last, slowest. @@ -244,11 +264,13 @@ class clutchlog void out(std::ostream& out) {_out = &out;} std::ostream& out() {return *_out;} +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 void depth(size_t d) {_depth = d;} size_t depth() const {return _depth;} void depth_mark(std::string mark) {_depth_mark = mark;} std::string depth_mark() const {return _depth_mark;} +#endif void threshold(level l) {_stage = l;} level threshold() const {return _stage;} @@ -351,30 +373,38 @@ class clutchlog std::string format( std::string format, const std::string& what, +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 const std::string& name, +#endif const level& stage, const std::string& file, const std::string& func, - const size_t line, + const size_t line +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + , const size_t depth +#endif ) const { format = replace(format, "\\{msg\\}", what); - format = replace(format, "\\{name\\}", name); format = replace(format, "\\{file\\}", file); format = replace(format, "\\{func\\}", func); format = replace(format, "\\{level\\}", _level_words.at(stage)); format = replace(format, "\\{line\\}", line); - format = replace(format, "\\{depth\\}", depth); std::string letter(1, _level_words.at(stage).at(0)); // char -> string format = replace(format, "\\{level_letter\\}", letter); +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + format = replace(format, "\\{name\\}", name); + format = replace(format, "\\{depth\\}", depth); + std::ostringstream chevrons; for(size_t i = _strip_calls; i < depth; ++i) { chevrons << ">"; } format = replace(format, "\\{depth_marks\\}", chevrons.str()); +#endif return format; } @@ -388,9 +418,16 @@ class clutchlog scope_t scope = locate(stage, file, func, line); if(scope.matches) { +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 *_out << format(_format_log, what, basename(getenv("_")), stage, file, func, line, scope.depth ); +#else + *_out << format(_format_log, what, + stage, file, func, + line ); + +#endif _out->flush(); } // if scopes.matches } @@ -428,9 +465,15 @@ class clutchlog std::ofstream fd(outfile); if(_format_dump.size() > 0) { +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 fd << format(_format_dump, "", basename(getenv("_")), stage, file, func, line, scope.depth ); +#else + fd << format(_format_dump, "", + stage, file, func, + line ); +#endif fd << sep; // sep after comment line. } @@ -479,11 +522,13 @@ class clutchlog void out(std::ostream&) {} std::ostream& out() {} +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 void depth(size_t) {} size_t depth() const {} void depth_mark(std::string) {} std::string depth_mark() const {} +#endif void threshold(level) {} level threshold() const {} @@ -519,12 +564,17 @@ class clutchlog std::string format( std::string, const std::string&, +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 const std::string&, +#endif const level&, const std::string&, const std::string&, - const size_t, const size_t +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + , + const size_t +#endif ) const { } diff --git a/tests/t-log.cpp b/tests/t-log.cpp index e7669c3..531e104 100644 --- a/tests/t-log.cpp +++ b/tests/t-log.cpp @@ -27,31 +27,41 @@ int main(/*const int argc, char* argv[]*/) log.out(std::clog); std::clog << "depth: 99; threshold: xdebug; location: .*" << std::endl; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 log.depth(99); +#endif log.threshold(clutchlog::level::xdebug); log.location(".*",".*"); f(); std::clog << "depth: 4; threshold: xdebug; location: ,*" << std::endl; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 log.depth(4); +#endif log.threshold(clutchlog::level::xdebug); log.location(".*"); f(); std::clog << "depth: 99; threshold: warning; location: .*" << std::endl; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 log.depth(99); +#endif log.threshold(clutchlog::level::warning); log.location(".*"); f(); std::clog << "depth: 99; threshold: xdebug; location: 'core','g'" << std::endl; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 log.depth(99); +#endif log.threshold(clutchlog::level::xdebug); log.location("core","g"); f(); std::clog << "depth: 99; threshold: debug; location: '.*','(g|h)'" << std::endl; +#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 log.depth(99); +#endif log.threshold(clutchlog::level::debug); log.location(".*","(g|h)"); f();