fix: portability patch for OS other than Linux

- Test for sys headers and disable depth/name if not found
- Update the doc and bump to 0.3.
This commit is contained in:
Johann Dreo 2020-09-19 18:20:07 +02:00
commit 3a4bdc0d57
4 changed files with 85 additions and 19 deletions

View file

@ -12,7 +12,7 @@ set(CMAKE_CXX_STANDARD 17)
## Current version ## Current version
set(VERSION_MAJOR 0 CACHE STRING "Major version number" ) 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" ) set(VERSION_PATCH 0 CACHE STRING "Patch version number" )
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH) mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH)

View file

@ -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 - *source code location*: you can ask to display messages called from given files, functions and line number, all based on
regular expressions. 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 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 You can change this behavior at compile time by setting the
`CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG` preprocessor variable `CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG` preprocessor variable
to the desired maximum log level, for example: to the desired maximum log level, for example:
``` ```cpp
// Will always allow to log everything even in Release mode. // Will always allow to log everything even in Release mode.
#define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::xdebug #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 Limitations
=========== ===========
Because the call stack depth and binary name access are system-dependent, Because the call stack depth and program name access are system-dependent,
Clutchlog is only implemented for Linux at the moment. 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 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. either define the `WITH_CLUTCHLOG` preprocessor variable.
If you're using CMake (or another modern build system), 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, only for the "Debug" build type,
which is usually what you want if you use clutchlog, anyway. which is usually what you want if you use clutchlog, anyway.

View file

@ -8,17 +8,19 @@
#include <fstream> #include <fstream>
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
// #include <iomanip>
#include <string> #include <string>
#include <limits> #include <limits>
#include <regex> #include <regex>
#include <map> #include <map>
// #ifdef __unix__ #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
#include <execinfo.h> #include <execinfo.h> // execinfo
#include <stdlib.h> #include <stdlib.h> // getenv
#include <libgen.h> #include <libgen.h> // basename
// #endif #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
#else
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
#endif
/********************************************************************** /**********************************************************************
* Enable by default in Debug builds. * Enable by default in Debug builds.
@ -36,12 +38,20 @@
#ifndef CLUTCHLOG_DEFAULT_FORMAT #ifndef CLUTCHLOG_DEFAULT_FORMAT
//! Default format of the messages. //! 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" #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 #endif // CLUTCHLOG_DEFAULT_FORMAT
#ifndef CLUTCHDUMP_DEFAULT_FORMAT #ifndef CLUTCHDUMP_DEFAULT_FORMAT
//! Default format of the comment line in file dump. //! 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}" #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 #endif // CLUTCHDUMP_DEFAULT_FORMAT
#ifndef CLUTCHDUMP_DEFAULT_SEP #ifndef CLUTCHDUMP_DEFAULT_SEP
@ -150,12 +160,14 @@ class clutchlog
_format_log(CLUTCHLOG_DEFAULT_FORMAT), _format_log(CLUTCHLOG_DEFAULT_FORMAT),
_format_dump(CLUTCHDUMP_DEFAULT_FORMAT), _format_dump(CLUTCHDUMP_DEFAULT_FORMAT),
_out(&std::clog), _out(&std::clog),
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
_depth(std::numeric_limits<size_t>::max() - _strip_calls), _depth(std::numeric_limits<size_t>::max() - _strip_calls),
_depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK),
#endif
_stage(level::error), _stage(level::error),
_in_file(".*"), _in_file(".*"),
_in_func(".*"), _in_func(".*"),
_in_line(".*"), _in_line(".*")
_depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK)
{} {}
protected: protected:
@ -164,22 +176,28 @@ class clutchlog
std::string _format_log; std::string _format_log;
std::string _format_dump; std::string _format_dump;
std::ostream* _out; std::ostream* _out;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
size_t _depth; size_t _depth;
std::string _depth_mark;
#endif
level _stage; level _stage;
std::regex _in_file; std::regex _in_file;
std::regex _in_func; std::regex _in_func;
std::regex _in_line; std::regex _in_line;
std::string _depth_mark;
struct scope_t { struct scope_t {
bool matches; // everything is compatible bool matches; // everything is compatible
level stage; // current log level level stage; // current log level
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
size_t depth; // current depth size_t depth; // current depth
#endif
bool there; // location is compatible bool there; // location is compatible
scope_t() : scope_t() :
matches(false), matches(false),
stage(level::xdebug), stage(level::xdebug),
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
depth(0), depth(0),
#endif
there(false) there(false)
{} {}
}; };
@ -203,6 +221,7 @@ class clutchlog
return scope; return scope;
} }
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
/***** Stack depth *****/ /***** Stack depth *****/
// Backtrace in second, quite fast. // Backtrace in second, quite fast.
const size_t max_buffer = 4096; const size_t max_buffer = 4096;
@ -214,6 +233,7 @@ class clutchlog
// Bypass if no match. // Bypass if no match.
return scope; return scope;
} }
#endif
/***** Location *****/ /***** Location *****/
// Location last, slowest. // Location last, slowest.
@ -244,11 +264,13 @@ class clutchlog
void out(std::ostream& out) {_out = &out;} void out(std::ostream& out) {_out = &out;}
std::ostream& out() {return *_out;} std::ostream& out() {return *_out;}
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
void depth(size_t d) {_depth = d;} void depth(size_t d) {_depth = d;}
size_t depth() const {return _depth;} size_t depth() const {return _depth;}
void depth_mark(std::string mark) {_depth_mark = mark;} void depth_mark(std::string mark) {_depth_mark = mark;}
std::string depth_mark() const {return _depth_mark;} std::string depth_mark() const {return _depth_mark;}
#endif
void threshold(level l) {_stage = l;} void threshold(level l) {_stage = l;}
level threshold() const {return _stage;} level threshold() const {return _stage;}
@ -351,30 +373,38 @@ class clutchlog
std::string format( std::string format(
std::string format, std::string format,
const std::string& what, const std::string& what,
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
const std::string& name, const std::string& name,
#endif
const level& stage, const level& stage,
const std::string& file, const std::string& file,
const std::string& func, const std::string& func,
const size_t line, const size_t line
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
,
const size_t depth const size_t depth
#endif
) const ) const
{ {
format = replace(format, "\\{msg\\}", what); format = replace(format, "\\{msg\\}", what);
format = replace(format, "\\{name\\}", name);
format = replace(format, "\\{file\\}", file); format = replace(format, "\\{file\\}", file);
format = replace(format, "\\{func\\}", func); format = replace(format, "\\{func\\}", func);
format = replace(format, "\\{level\\}", _level_words.at(stage)); format = replace(format, "\\{level\\}", _level_words.at(stage));
format = replace(format, "\\{line\\}", line); format = replace(format, "\\{line\\}", line);
format = replace(format, "\\{depth\\}", depth);
std::string letter(1, _level_words.at(stage).at(0)); // char -> string std::string letter(1, _level_words.at(stage).at(0)); // char -> string
format = replace(format, "\\{level_letter\\}", letter); 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; std::ostringstream chevrons;
for(size_t i = _strip_calls; i < depth; ++i) { for(size_t i = _strip_calls; i < depth; ++i) {
chevrons << ">"; chevrons << ">";
} }
format = replace(format, "\\{depth_marks\\}", chevrons.str()); format = replace(format, "\\{depth_marks\\}", chevrons.str());
#endif
return format; return format;
} }
@ -388,9 +418,16 @@ class clutchlog
scope_t scope = locate(stage, file, func, line); scope_t scope = locate(stage, file, func, line);
if(scope.matches) { if(scope.matches) {
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
*_out << format(_format_log, what, basename(getenv("_")), *_out << format(_format_log, what, basename(getenv("_")),
stage, file, func, stage, file, func,
line, scope.depth ); line, scope.depth );
#else
*_out << format(_format_log, what,
stage, file, func,
line );
#endif
_out->flush(); _out->flush();
} // if scopes.matches } // if scopes.matches
} }
@ -428,9 +465,15 @@ class clutchlog
std::ofstream fd(outfile); std::ofstream fd(outfile);
if(_format_dump.size() > 0) { if(_format_dump.size() > 0) {
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
fd << format(_format_dump, "", basename(getenv("_")), fd << format(_format_dump, "", basename(getenv("_")),
stage, file, func, stage, file, func,
line, scope.depth ); line, scope.depth );
#else
fd << format(_format_dump, "",
stage, file, func,
line );
#endif
fd << sep; // sep after comment line. fd << sep; // sep after comment line.
} }
@ -479,11 +522,13 @@ class clutchlog
void out(std::ostream&) {} void out(std::ostream&) {}
std::ostream& out() {} std::ostream& out() {}
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
void depth(size_t) {} void depth(size_t) {}
size_t depth() const {} size_t depth() const {}
void depth_mark(std::string) {} void depth_mark(std::string) {}
std::string depth_mark() const {} std::string depth_mark() const {}
#endif
void threshold(level) {} void threshold(level) {}
level threshold() const {} level threshold() const {}
@ -519,12 +564,17 @@ class clutchlog
std::string format( std::string format(
std::string, std::string,
const std::string&, const std::string&,
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
const std::string&, const std::string&,
#endif
const level&, const level&,
const std::string&, const std::string&,
const std::string&, const std::string&,
const size_t,
const size_t const size_t
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
,
const size_t
#endif
) const ) const
{ } { }

View file

@ -27,31 +27,41 @@ int main(/*const int argc, char* argv[]*/)
log.out(std::clog); log.out(std::clog);
std::clog << "depth: 99; threshold: xdebug; location: .*" << std::endl; std::clog << "depth: 99; threshold: xdebug; location: .*" << std::endl;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(99); log.depth(99);
#endif
log.threshold(clutchlog::level::xdebug); log.threshold(clutchlog::level::xdebug);
log.location(".*",".*"); log.location(".*",".*");
f(); f();
std::clog << "depth: 4; threshold: xdebug; location: ,*" << std::endl; std::clog << "depth: 4; threshold: xdebug; location: ,*" << std::endl;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(4); log.depth(4);
#endif
log.threshold(clutchlog::level::xdebug); log.threshold(clutchlog::level::xdebug);
log.location(".*"); log.location(".*");
f(); f();
std::clog << "depth: 99; threshold: warning; location: .*" << std::endl; std::clog << "depth: 99; threshold: warning; location: .*" << std::endl;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(99); log.depth(99);
#endif
log.threshold(clutchlog::level::warning); log.threshold(clutchlog::level::warning);
log.location(".*"); log.location(".*");
f(); f();
std::clog << "depth: 99; threshold: xdebug; location: 'core','g'" << std::endl; std::clog << "depth: 99; threshold: xdebug; location: 'core','g'" << std::endl;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(99); log.depth(99);
#endif
log.threshold(clutchlog::level::xdebug); log.threshold(clutchlog::level::xdebug);
log.location("core","g"); log.location("core","g");
f(); f();
std::clog << "depth: 99; threshold: debug; location: '.*','(g|h)'" << std::endl; std::clog << "depth: 99; threshold: debug; location: '.*','(g|h)'" << std::endl;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(99); log.depth(99);
#endif
log.threshold(clutchlog::level::debug); log.threshold(clutchlog::level::debug);
log.location(".*","(g|h)"); log.location(".*","(g|h)");
f(); f();