adds value-dependant template tags

Implements #4 #5 #7
This commit is contained in:
Johann Dreo 2023-01-28 15:21:06 +01:00
commit c45080fc8e
3 changed files with 165 additions and 15 deletions

View file

@ -200,12 +200,15 @@ Available tags are:
- `{file}`: the current file (absolute path),
- `{func}`: the current function,
- `{line}`: the current line number,
- `{level_fmt}`: the format of the current level (i.e. configured with `clutchlog::style`).
- `{level_fmt}`: the style of the current level (i.e. configured with `clutchlog::style`),
- `{filehash_fmt}`: a style for file names, which is value-dependant (see `clutchlog::filehash_styles`),
- `{funchash_fmt}`: a style for function names, which is value-dependant (see `clutchlog::funchash_styles`).
Some tags are only available on POSIX operating systems as of now:
- `{name}`: the name of the current binary,
- `{depth}`: the current depth of the call stack,
- `{depth_marks}`: as many chevrons `>` as there is calls in the stack,
- `{depth_fmt}`: a style depending on the current depth value (see `clutchlog::depth_styles`),
- `{hfill}`: Inserts a sequence of characters that will stretch to fill the space available
in the current terminal, between the rightmost and leftmost part of the log message.
@ -220,10 +223,12 @@ clutchlog will not put the location-related tags in the message formats
(i.e. `{name}`, `{func}`, and `{line}`) when not in Debug builds.
Output style
------------
Output Styling
--------------
Output lines can be colored differently depending on the log level.
Output lines can be styled differently depending on their content.
For example, output lines can be colored differently depending on the log level.
```cpp
// Print error messages in bold red:
log.style(level::error, // First, the log level.
@ -251,7 +256,8 @@ depending on the types of arguments passed to styling functions:
- `clutchlog::fg::none` and `clutchlog::bg::none` can be passed in all modes.
For example, all the following lines encode
a bright red foreground for the critical level:
a bright red foreground for the critical level
(see the "Colors" section below):
```cpp
log.style(level:critical,
fmt::fg::red); // 16-colors mode.
@ -371,6 +377,42 @@ log.style(level::info, fg::none, 100,0,0, typo::bold); // No color over bold dar
```
### Value-dependant Format Tags
Some tags can be used to change the style of (part of) the output line,
*depending on its content*.
The `{filehash_fmt}` and `{funchash_fmt}` will introduce a styling sequence
which depends on the current file name, and function name respectively.
The chosen style is chosen at random among the candidate ones,
but will always be the same for each value.
The set of candidate styles can be configured with `clutchlog::filehash_styles`
and `clutchlog::funchash_styles`, which both take a vector of `clutchlog::fmt`
objects as argument:
```cpp
// Either one or the other color for filenames:
log.filehash_styles( { fmt(fg::red), fmt(fg::yellow) } );
// This would fix the function name style to a single one:
log.funchash_styles( { fmt(typo::bold) } );
// Works with any `fmt` constructor
// (here, shades of blues in 256-colors mode):
log.funchash_styles( { fmt(33), fmt(27), fmt(39), fmt(45) } );
```
The same idea applies to `{depth_fmt}`.
However, if `clutchlog::depth_styles` is configured,
then the styles are chosen *in order*.
That is, a depth of 1 would lead to the first style being chosen.
If the current depth of the stack is larger than the number of configured
styles, then the last one is used.
For example:
```cpp
// Increasingly darker depth level colors (using the 256-colors mode).
log.depth_styles({ fmt(255), fmt(250), fmt(245), fmt(240), fmt(235) });
```
Advanced Usage
==============

View file

@ -810,6 +810,16 @@ class clutchlog
this->print_on(os);
return os.str();
}
static fmt hash( const std::string& str, const std::vector<fmt> domain = {})
{
size_t h = std::hash<std::string>{}(str);
if(domain.size() == 0) {
return fmt(static_cast<short>(h % 256));
} else {
return fmt(domain[h % domain.size()]);
}
}
}; // fmt class
/** @} */
@ -872,6 +882,10 @@ class clutchlog
_in_file(".*"),
_in_func(".*"),
_in_line(".*")
// Empty vectors by default:
// _filehash_fmts
// _funchash_fmts
// _depth_fmts
{
// Reverse the level->word map into a word->level map.
for(auto& lw : _level_word) {
@ -926,9 +940,16 @@ class clutchlog
/** Current line location filter. */
std::regex _in_line;
/** List of candidate format objects for value-dependant file name styling. */
std::vector<fmt> _filehash_fmts;
/** List of candidate format objects for value-dependant function name styling. */
std::vector<fmt> _funchash_fmts;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
/** Maximum buffer size for backtrace message. */
static const size_t _max_buffer = 4096;
/** Ordered list of format objects for value-dependant depth styling. */
std::vector<fmt> _depth_fmts;
#endif
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
@ -974,11 +995,11 @@ class clutchlog
size_t strip_calls() const {return _strip_calls;}
#endif
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
//! Set the character for the stretching hfill marker.
//! Set the character for the stretching `{hfill}` template tag marker.
void hfill_mark(const char mark) {_hfill_char = mark;}
//! Get the character for the stretching hfill marker.
//! Get the character for the stretching `{hfill}` template tag marker.
char hfill_mark() const {return _hfill_char;}
//! Set the style for the stretching hfill marker, with a `fmt` object.
//! Set the style for the stretching `{hfill}` template tag marker, with a `fmt` object.
void hfill_style(fmt style) {_hfill_fmt = style;}
/** Set the style for the stretching hfill marker.
*
@ -986,17 +1007,42 @@ class clutchlog
*/
template<class ... FMT>
void hfill_style(FMT... styles) { this->hfill_style(fmt(styles...)); }
//! Get the character for the stretching hfill marker.
//! Get the character for the stretching `{hfill}` template tag marker.
fmt hfill_style() const {return _hfill_fmt;}
//! Set the maximum width for which to hfill. */
//! Set the maximum width for which to `{hfill}`.
void hfill_max(const size_t nmax) {_hfill_max = nmax;}
//! Get the maximum width for which to hfill. */
//! Get the maximum width for which to `{hfill}`.
size_t hfill_max() {return _hfill_max;}
//! Set the minimum width at which to hfill. */
//! Set the minimum width at which to `{hfill}`.
void hfill_min(const size_t nmin) {_hfill_min = nmin;}
//! Get the minimum width at which to hfill. */
//! Get the minimum width at which to `{hfill}`.
size_t hfill_min() {return _hfill_min;}
#endif
/** Set the candidate styles for value-dependant file name formatting.
*
* Style will be chosen based on the hash value of the filename
* among the candidate ones.
*
* See the `{filehash_fmt}` template tag.
*/
void filehash_styles(std::vector<fmt> styles) {_filehash_fmts = styles;}
/** Set the candidate styles for value-dependant function name formatting.
*
* Style will be chosen based on the hash value of the filename
* among the candidate ones.
*
* See the `{funchash_fmt}` template tag.
*/
void funchash_styles(std::vector<fmt> styles) {_funchash_fmts = styles;}
/** Set the styles for value-dependant depth formatting.
*
* The given list should be ordered, styles will be applied
* for the corresponding depth level. If the actual depth is
* larger than the number of styles, the last one is used.
*
* See the `{depth_fmt}` template tag.
*/
void depth_styles(std::vector<fmt> styles) {_depth_fmts = styles;}
//! Set the log level (below which logs are not printed) with an identifier.
void threshold(level l) {_stage = l;}
@ -1238,17 +1284,26 @@ class clutchlog
row = replace(row, "\\{level_short\\}", _level_short.at(stage));
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
size_t actual_depth = depth - _strip_calls;
row = replace(row, "\\{name\\}", name);
row = replace(row, "\\{depth\\}", depth - _strip_calls);
row = replace(row, "\\{depth\\}", actual_depth);
std::ostringstream chevrons;
for(size_t i = _strip_calls; i < depth; ++i) {
chevrons << _depth_mark;
}
row = replace(row, "\\{depth_marks\\}", chevrons.str());
#endif
if(_depth_fmts.size() == 0) {
row = replace(row, "\\{depth_fmt\\}", fmt(actual_depth % 256).str() );
} else {
row = replace(row, "\\{depth_fmt\\}",
_depth_fmts[std::min(actual_depth,_depth_fmts.size()-1)].str() );
}
#endif
row = replace(row, "\\{level_fmt\\}", _level_fmt.at(stage).str());
row = replace(row, "\\{filehash_fmt\\}", fmt::hash(file, _filehash_fmts).str() );
row = replace(row, "\\{funchash_fmt\\}", fmt::hash(func, _funchash_fmts).str() );
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
// hfill is replaced last to allow for correct line width estimation.
@ -1490,6 +1545,7 @@ class clutchlog
friend std::ostream& operator<<(std::ostream&, const fmt&) {}
std::string operator()( const std::string&) const {}
std::string str() const {}
static fmt hash( const std::string&, const std::vector<fmt>) {}
};
public:
clutchlog(clutchlog const&) = delete;
@ -1534,6 +1590,9 @@ class clutchlog
void hfill_max(const size_t) {}
size_t hfill_max() {}
#endif
void filehash_styles(std::vector<fmt> ) {}
void funchash_styles(std::vector<fmt> ) {}
void depth_styles(std::vector<fmt>) {}
void threshold(level) {}
void threshold(const std::string&) {}

49
tests/t-hash-color.cpp Normal file
View file

@ -0,0 +1,49 @@
#include <iostream>
#include <limits>
#include "../clutchlog/clutchlog.h"
void deepcall()
{
CLUTCHLOG(warning,"at depth 4");
}
void subsubsubcall()
{
CLUTCHLOG(warning,"at depth 3");
deepcall();
}
void subsubcall()
{
CLUTCHLOG(warning,"at depth 2");
subsubsubcall();
}
void subcall()
{
CLUTCHLOG(warning,"at depth 1");
subsubcall();
}
int main(/*const int argc, char* argv[]*/)
{
auto& log = clutchlog::logger();
using fmt = clutchlog::fmt;
using typo = clutchlog::fmt::typo;
fmt reset(typo::reset);
std::ostringstream tpl;
tpl << "{level_fmt}Having a {level} {filehash_fmt}within {file} {funchash_fmt}calling {func} {depth_fmt}at level {depth}"
<< reset << " : {msg}\n";
log.format(tpl.str());
log.threshold(clutchlog::level::xdebug);
log.filehash_styles( {fmt(fmt::fg::red), fmt(fmt::fg::yellow)} );
log.funchash_styles( {fmt(fmt::fg::green), fmt(fmt::fg::blue),
fmt(fmt::fg::bright_green), fmt(fmt::fg::bright_blue), fmt(fmt::fg::magenta)} );
log.depth_styles( {fmt(255),fmt(250),fmt(245),fmt(240)} );
CLUTCHLOG(warning,"in main");
subcall();
}