feat(levels): easier threshold setting.

- Adds `threshold(string)` for easier level setting.
- Adds `levels()` to make it easy to test if a user-defined string is good.
- Move the log levels section up in the readme.
This commit is contained in:
Johann Dreo 2022-08-29 10:24:17 +02:00
commit 76e4782cb0
3 changed files with 79 additions and 64 deletions

View file

@ -40,7 +40,7 @@ To configure the display, you indicate the three types of locations, for example
```cpp ```cpp
auto& log = clutchlog::logger(); auto& log = clutchlog::logger();
log.depth(2); // Log functions called from "main" but not below. log.depth(2); // Log functions called from "main" but not below.
log.threshold(clutchlog::level::info); // Log only "info", "warning", "error" or "critical" messages. log.threshold("Info"); // Log only "info", "warning", "error" or "critical" messages.
log.file("algebra/.*"); // Will match any file in the "algebra" directory. log.file("algebra/.*"); // Will match any file in the "algebra" directory.
log.func("(mul|add|sub|div)"); // Will match "multiply", for instance. log.func("(mul|add|sub|div)"); // Will match "multiply", for instance.
``` ```
@ -72,6 +72,24 @@ allowing for the fast tracking of a bug across the execution.
API documentation API documentation
================= =================
Log level semantics
-------------------
Log levels use a classical semantics for a human skilled in the art, in decreasing order of importance:
- *Critical*: an error that cannot be recovered. For instance, something which will make a server stop right here.
- *Error*: an error that invalidates a function, but may still be recovered. For example, a bad user input that will make a server reset its state, but not crash.
- *Warning*: something that is strange, but is probably legit. For example a default parameter is set because the user forgot to indicate its preference.
- *Progress*: the state at which computation currently is.
- *Note*: some state worth noting to understand what's going on.
- *Info*: any information that would help ensuring that everything is going well.
- *Debug*: data that would help debugging the program if there was a bug later on.
- *XDebug*: debugging information that would be heavy to read.
Note: the log levels constants are lower case (for example: `clutchlog::level::xdebug`), but their string representation is not (e.g. "XDebug", this should be taken into account when using `threshold` or `level_of`).
Calls Calls
----- -----
@ -135,9 +153,9 @@ A shortcut function can be used to filter all at once:
log.location(file, func, line); // Defaults to any, second and last parameters being optional. log.location(file, func, line); // Defaults to any, second and last parameters being optional.
``` ```
Strings may be used to set up the threshold, using `level_of`: Strings may be used to set up the threshold:
```cpp ```cpp
log.threshold( log.level_of("XDebug") ); // You have to know the exact string. log.threshold("Error"); // You have to know the exact —case sensitive— string.
``` ```
Note that the case of the log levels strings matters (see below). Note that the case of the log levels strings matters (see below).
@ -305,6 +323,11 @@ log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), CLUTCHLOC, "dumped_
log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), "main.cpp", "main", 122, "dumped.dat", "\n\n"); log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), "main.cpp", "main", 122, "dumped.dat", "\n\n");
``` ```
You can access the identifier of log levels with `level_of`:
```cpp
log.threshold( log.level_of("XDebug") ); // You have to know the exact string.
```
(De)clutch any function call (De)clutch any function call
---------------------------- ----------------------------
@ -332,22 +355,6 @@ CLUTCHCODE(info,
); );
``` ```
Log level semantics
===================
Log levels use a classical semantics for a human skilled in the art, in decreasing order of importance:
- *Critical*: an error that cannot be recovered. For instance, something which will make a server stop right here.
- *Error*: an error that invalidates a function, but may still be recovered. For example, a bad user input that will make a server reset its state, but not crash.
- *Warning*: something that is strange, but is probably legit. For example a default parameter is set because the user forgot to indicate its preference.
- *Progress*: the state at which computation currently is.
- *Note*: some state worth noting to understand what's going on.
- *Info*: any information that would help ensuring that everything is going well.
- *Debug*: data that would help debugging the program if there was a bug later on.
- *XDebug*: debugging information that would be heavy to read.
Note: the log levels constants are lower case (for example: `clutchlog::level::xdebug`), but their string representation is not (e.g. "XDebug", this should be taken into account when using `level_of`).
Limitations Limitations
=========== ===========

View file

@ -282,16 +282,16 @@ class clutchlog
} /** Typographic style*/ style; } /** Typographic style*/ style;
//! Empty constructor, only useful for a no-op formatter. //! Empty constructor, only useful for a no-op formatter.
fmt() : fore(fg::none), back(bg::none), style(typo::none) { } fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
/** @name All combination of constructors with different parameters orders. /** @name All combination of constructors with different parameters orders.
* @{ */ * @{ */
fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { } fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { } fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { } fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { } fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { } fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { } fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
/** @} */ /** @} */
protected: protected:
@ -472,10 +472,28 @@ class clutchlog
std::string depth_mark() const {return _depth_mark;} std::string depth_mark() const {return _depth_mark;}
#endif #endif
//! Set the log level below which logs are not printed. //! Set the log level (below which logs are not printed) with an identifier.
void threshold(level l) {_stage = l;} void threshold(level l) {_stage = l;}
//! Set the log level (below which logs are not printed) with a string.
void threshold(const std::string& l) {_stage = this->level_of(l);}
//! Get the log level below which logs are not printed. //! Get the log level below which logs are not printed.
level threshold() const {return _stage;} level threshold() const {return _stage;}
//! Get the map of available log levels string representations toward their identifier. */
const std::map<std::string,level>& levels() const { return _word_level;}
/** Return the log level tag corresponding to the given pre-configured name.
*
* @note This is case sensitive, see the pre-configured `_level_word`.
*/
level level_of(const std::string name)
{
const auto ilevel = _word_level.find(name);
if( ilevel != std::end(_word_level)) {
return ilevel->second;
} else {
throw std::out_of_range("'" + name + "' is not a valid log level name");
}
}
//! Set the regular expression filtering the file location. //! Set the regular expression filtering the file location.
void file(std::string file) {_in_file = file;} void file(std::string file) {_in_file = file;}
@ -507,20 +525,6 @@ class clutchlog
//! Get the configured fmt instance of the given log level. //! Get the configured fmt instance of the given log level.
fmt style(level stage) const { return _level_fmt.at(stage); } fmt style(level stage) const { return _level_fmt.at(stage); }
/** Return the log level tag corresponding to the given pre-configured name.
*
* @note This is case sensitive, see the pre-configured `_level_word`.
*/
level level_of(const std::string name)
{
const auto ilevel = _word_level.find(name);
if( ilevel != std::end(_word_level)) {
return ilevel->second;
} else {
throw std::out_of_range("'" + name + "' is not a valid log level name");
}
}
/** @} */ /** @} */
public: public:
@ -815,25 +819,25 @@ class clutchlog
class clutchlog class clutchlog
{ {
public: public:
static clutchlog& logger() { } static clutchlog& logger() {}
enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7}; enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
class fmt { class fmt {
public: public:
enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore; enum class fg { black, red, green, yellow, blue, magenta, cyan, white, none } fore;
enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back; enum class bg { black, red, green, yellow, blue, magenta, cyan, white, none } back;
enum class typo { reset, bold, underline, inverse, none } style; enum class typo { reset, bold, underline, inverse, none } style;
fmt() : fore(fg::none), back(bg::none), style(typo::none) { } fmt() : fore(fg::none), back(bg::none), style(typo::none) {}
fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { } fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { } fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { } fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) {}
fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) { } fmt( bg b, typo s , fg f = fg::none) : fore(f), back(b), style(s) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) { } fmt(typo s, fg f = fg::none, bg b = bg::none) : fore(f), back(b), style(s) {}
fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) { } fmt(typo s, bg b , fg f = fg::none) : fore(f), back(b), style(s) {}
protected: protected:
std::ostream& print_on(std::ostream&) const { } std::ostream& print_on(std::ostream&) const {}
public: public:
friend std::ostream& operator<<(std::ostream&, const fmt&) { } friend std::ostream& operator<<(std::ostream&, const fmt&) {}
std::string operator()(const std::string&) const { } std::string operator()(const std::string&) const {}
}; };
public: public:
clutchlog(clutchlog const&) = delete; clutchlog(clutchlog const&) = delete;
@ -848,7 +852,7 @@ class clutchlog
const std::string&, const std::string&,
const size_t const size_t
) const ) const
{ } {}
public: public:
void format(const std::string&) {} void format(const std::string&) {}
std::string format() const {} std::string format() const {}
@ -868,7 +872,10 @@ class clutchlog
#endif #endif
void threshold(level) {} void threshold(level) {}
void threshold(const std::string&) {}
level threshold() const {} level threshold() const {}
const std::map<std::string,level> levels() const {};
level level_of(const std::string) {}
void file(std::string) {} void file(std::string) {}
void func(std::string) {} void func(std::string) {}
@ -881,25 +888,24 @@ class clutchlog
const std::string& in_function=".*", const std::string& in_function=".*",
const std::string& in_line=".*" const std::string& in_line=".*"
) )
{ } {}
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
void style(level, fmt) { } void style(level, fmt) {}
fmt style(level) const { } fmt style(level) const {}
level level_of(const std::string) { }
public: public:
std::string replace( std::string replace(
const std::string&, const std::string&,
const std::string&, const std::string&,
const std::string& const std::string&
) const ) const
{ } {}
std::string replace( std::string replace(
const std::string&, const std::string&,
const std::string&, const std::string&,
const size_t const size_t
) const ) const
{ } {}
std::string format( std::string format(
std::string, std::string,
@ -916,14 +922,14 @@ class clutchlog
const size_t const size_t
#endif #endif
) const ) const
{ } {}
void log( void log(
const level&, const level&,
const std::string&, const std::string&,
const std::string&, const std::string&, size_t const std::string&, const std::string&, size_t
) const ) const
{ } {}
template<class In> template<class In>
void dump( void dump(
@ -933,7 +939,7 @@ class clutchlog
const std::string&, const std::string&,
const std::string const std::string
) const ) const
{ } {}
}; };
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif // WITH_CLUTCHLOG #endif // WITH_CLUTCHLOG

View file

@ -38,7 +38,9 @@ int main(/*const int argc, char* argv[]*/)
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(4); log.depth(4);
#endif #endif
log.threshold(clutchlog::level::xdebug); assert(log.levels().find("XDebug") != std::end(log.levels())); // contains
assert(log.levels().find("Xdebug") == std::end(log.levels())); // not contains
log.threshold("XDebug");
log.location(".*"); log.location(".*");
f(); f();
@ -62,7 +64,7 @@ int main(/*const int argc, char* argv[]*/)
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
log.depth(99); log.depth(99);
#endif #endif
log.threshold(clutchlog::level::debug); log.threshold("Debug");
log.location(".*","(g|h)"); log.location(".*","(g|h)");
f(); f();
} }