feats: adds {level_fmt} and fix hfill accordingly
Update t-demo to show more formatting.
This commit is contained in:
parent
2d094b2637
commit
1c6a6d8507
3 changed files with 119 additions and 58 deletions
34
README.md
34
README.md
|
|
@ -132,7 +132,7 @@ Log levels use a classical semantics for a human skilled in the art, in decreasi
|
|||
- *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`).
|
||||
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 `clutchlog::threshold` or `clutchlog::level_of`).
|
||||
|
||||
|
||||
Location filtering
|
||||
|
|
@ -174,12 +174,12 @@ Note that the case of the log levels strings matters (see below).
|
|||
Output Configuration
|
||||
--------------------
|
||||
|
||||
The output stream can be configured using the `out` method:
|
||||
The output stream can be configured using the `clutchlog::out` method:
|
||||
```cpp
|
||||
log.out(std::clog); // Defaults to clog.
|
||||
```
|
||||
|
||||
The format of the messages can be defined with the `format` method, passing a string with standardized tags surrounded by `{}`:
|
||||
The format of the messages can be defined with the `clutchlog::format` method, passing a string with standardized tags surrounded by `{}`:
|
||||
```cpp
|
||||
log.format("{msg}");
|
||||
```
|
||||
|
|
@ -213,7 +213,7 @@ clutchlog will not put the location-related tags in the message formats
|
|||
Output style
|
||||
------------
|
||||
|
||||
The output can be colored differently depending on the log level.
|
||||
Output lines can be colored differently depending on the log level.
|
||||
```cpp
|
||||
// Print error messages in bold red:
|
||||
log.style(clutchlog::level::error, // First, the log level.
|
||||
|
|
@ -229,6 +229,9 @@ fmt warn(fmt::fg::magenta, fmt::typo::bold);
|
|||
log.style(clutchlog::level::warning, warn);
|
||||
```
|
||||
|
||||
Note: this inserts a style marker at the very beginning of the line.
|
||||
If you add other styles later on the line, they will take precedence.
|
||||
|
||||
Using the `clutchlog::fmt` class, you can style:
|
||||
|
||||
- the foreground color, passing a `clutchlog::fmt::fg`,
|
||||
|
|
@ -272,11 +275,14 @@ log.format(format.str());
|
|||
Note: messages at the "critical", "error" and "warning" log levels are colored by default.
|
||||
You may want to set their style to `none` if you want to stay in control of inserted colors in the format template.
|
||||
|
||||
The horizontal filling line (the `{hfill}` tag) can be configured separately with `hfill_style`,
|
||||
The horizontal filling line (the `{hfill}` tag) can be configured separately with `clutchlog::hfill_style`,
|
||||
for example:
|
||||
```cpp
|
||||
log.hfill_style(clutchlog::fmt::fg::black);
|
||||
```
|
||||
Note: this will actually reset any styling after the hfill,
|
||||
disabling any style you would have set for the whole message using `clutchlog::format`
|
||||
for the remaining of the message.
|
||||
|
||||
|
||||
Advanced Usage
|
||||
|
|
@ -304,13 +310,13 @@ clutchlog will not put the location-related tags in the message formats
|
|||
|
||||
### Marks
|
||||
|
||||
The mark used with the `{depth_marks}` tag can be configured with the `depth_mark` method,
|
||||
The mark used with the `{depth_marks}` tag can be configured with the `clutchlog::depth_mark` method,
|
||||
and its default with the `CLUTCHLOG_DEFAULT_DEPTH_MARK` macro:
|
||||
```cpp
|
||||
log.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); // Defaults to ">".
|
||||
```
|
||||
|
||||
The character used with the `{hfill}` tag can be configured wth the `hfill_mark` method,
|
||||
The character used with the `{hfill}` tag can be configured wth the `clutchlog::hfill_mark` method,
|
||||
and its default with the `CLUTCHLOG_DEFAULT_HFILL_MARK` macro:
|
||||
```cpp
|
||||
log.hfill_mark(CLUTCHLOG_DEFAULT_HFILL_MARK); // Defaults to '.'.
|
||||
|
|
@ -318,13 +324,13 @@ log.hfill_mark(CLUTCHLOG_DEFAULT_HFILL_MARK); // Defaults to '.'.
|
|||
|
||||
Clutchlog measures the width of the standard error channel.
|
||||
If it is redirected, it may be measured as very large.
|
||||
Thus, the `hfill_max` accessors allow to set a maximum width (in number of characters).
|
||||
Thus, the `clutchlog::hfill_max` accessors allow to set a maximum width (in number of characters).
|
||||
```cpp
|
||||
log.hfill_max(CLUTCHLOG_DEFAULT_HFILL_MAX); // Defaults to 300.
|
||||
```
|
||||
Note: clutchlog will select the minimum between `hfill_max`
|
||||
Note: clutchlog will select the minimum between `clutchlog::hfill_max`
|
||||
and the measured number of columns in the terminal,
|
||||
so that you may use `hfill_max` as a way to constraint the output width
|
||||
so that you may use `clutchlog::hfill_max` as a way to constraint the output width
|
||||
in any cases.
|
||||
|
||||
|
||||
|
|
@ -333,7 +339,7 @@ in any cases.
|
|||
By default, clutchlog removes 5 levels of the calls stack, so that your `main`
|
||||
entrypoint corresponds to a depth of zero.
|
||||
You can change this behaviour by defining the `CLUTCHLOG_STRIP_CALLS` macro,
|
||||
or calling `strip_calls`.
|
||||
or calling `clutchlog::strip_calls`.
|
||||
```cpp
|
||||
log.strip_calls(CLUTCHLOG_STRIP_CALLS); // Defaults to 5.
|
||||
```
|
||||
|
|
@ -378,7 +384,7 @@ for example:
|
|||
std::string mark = log.depth_mark();
|
||||
```
|
||||
|
||||
To control more precisely the logging, one can use the low-level `log` method:
|
||||
To control more precisely the logging, one can use the low-level `clutchlog::log` method:
|
||||
```cpp
|
||||
log.log(clutchlog::level::xdebug, "hello world", "main.cpp", "main", 122);
|
||||
```
|
||||
|
|
@ -392,7 +398,7 @@ 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");
|
||||
```
|
||||
|
||||
You can access the identifier of log levels with `level_of`:
|
||||
You can access the identifier of log levels with `clutchlog::level_of`:
|
||||
```cpp
|
||||
log.threshold( log.level_of("XDebug") ); // You have to know the exact string.
|
||||
```
|
||||
|
|
@ -474,7 +480,7 @@ And here are all the functions you may call to log something:
|
|||
CLUTCHDUMP(note, my_list, "my_list_{n}.dat");
|
||||
|
||||
// Function call.
|
||||
CLUTCHFUNC(warning, my_check, x, y); // Calls `my_check(x,y);`
|
||||
CLUTCHFUNC(warning, my_check, x, y); // Calls: my_check(x,y);
|
||||
|
||||
// Declutchable asserts.
|
||||
#define ASSERT(...) { CLUTCHFUNC(critical, assert, __VA_ARGS__) }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#ifndef CLUTCHLOG_H
|
||||
//! Header guard.
|
||||
#define CLUTCHLOG_H
|
||||
|
||||
/** @file */
|
||||
|
|
@ -22,7 +23,7 @@
|
|||
#include <regex>
|
||||
#include <map>
|
||||
|
||||
//! POSIX headers necessary for stack depth management are available.
|
||||
//! True if POSIX headers necessary for stack depth management are available.
|
||||
#if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
|
||||
#include <execinfo.h> // execinfo
|
||||
#include <stdlib.h> // getenv
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
|
||||
#endif
|
||||
|
||||
//! True if the system can handle the `hfill` feature.
|
||||
#if __has_include(<sys/ioctl.h>) && __has_include(<stdio.h>) && __has_include(<unistd.h>)
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -57,7 +59,7 @@
|
|||
**********************************************************************/
|
||||
#ifdef WITH_CLUTCHLOG
|
||||
|
||||
/** @addtogroup DefaultConfigMacros Default configuration macros
|
||||
/** @defgroup DefaultConfig Default configuration management
|
||||
* @{ **/
|
||||
|
||||
#ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
|
||||
|
|
@ -65,10 +67,10 @@
|
|||
#define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
|
||||
#endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
|
||||
|
||||
/** @} */
|
||||
/** @} DefaultConfig */
|
||||
|
||||
|
||||
/** @addtogroup UseMacros High-level API macros
|
||||
/** @defgroup UseMacros High-level API macros
|
||||
* @{ */
|
||||
|
||||
//! Handy shortcuts to location.
|
||||
|
|
@ -150,7 +152,7 @@
|
|||
} while(0)
|
||||
#endif // NDEBUG
|
||||
|
||||
/** @} */
|
||||
/** @} UseMacros */
|
||||
|
||||
#else // not WITH_CLUTCHLOG
|
||||
// Disabled macros can still be called in Release builds.
|
||||
|
|
@ -165,18 +167,20 @@
|
|||
**********************************************************************/
|
||||
|
||||
#ifdef WITH_CLUTCHLOG
|
||||
/** @defgroup Main Main class
|
||||
* @{
|
||||
*/
|
||||
/** The single class which holds everything.
|
||||
*
|
||||
* This is a Singleton class.
|
||||
*
|
||||
* @addtogroup Main Main class
|
||||
* @{
|
||||
*/
|
||||
class clutchlog
|
||||
{
|
||||
protected:
|
||||
|
||||
/** @addtogroup UseMacros High-level API macros
|
||||
/** @name Default configuration members
|
||||
* @{ */
|
||||
/** @ingroup DefaultConfig
|
||||
* @{ */
|
||||
#ifndef NDEBUG
|
||||
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
||||
|
|
@ -265,10 +269,11 @@ class clutchlog
|
|||
#endif
|
||||
#endif
|
||||
//! Default maximum number of character used as a filling for right-align the right part of messages with "{hfill}".
|
||||
static inline unsigned short default_hfill_max = CLUTCHLOG_HFILL_MAX;
|
||||
static inline size_t default_hfill_max = CLUTCHLOG_HFILL_MAX;
|
||||
|
||||
// NOTE: there is no CLUTCHLOG_HFILL_STYLE for defaulting,
|
||||
// but you can still set `hfill_style(...)` on the logger singleton.
|
||||
/* @} DefaultConfig */
|
||||
/* @} */
|
||||
|
||||
|
||||
|
|
@ -297,9 +302,6 @@ class clutchlog
|
|||
/** @addtogroup Formating Formating tools
|
||||
* @{ */
|
||||
|
||||
/** @name Formating API
|
||||
* @{ */
|
||||
|
||||
/** Color and style formatter for ANSI terminal escape sequences.
|
||||
*
|
||||
* @note All styles may not be supported by a given terminal/operating system.
|
||||
|
|
@ -410,10 +412,18 @@ class clutchlog
|
|||
reset.print_on(os);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/** Return the formatting code as a string.
|
||||
*/
|
||||
std::string str() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
this->print_on(os);
|
||||
return os.str();
|
||||
}
|
||||
}; // fmt class
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
/** @name Internal details
|
||||
* @{ */
|
||||
|
|
@ -470,7 +480,7 @@ class clutchlog
|
|||
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
|
||||
struct winsize w;
|
||||
ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
|
||||
_nb_columns = std::min(w.ws_col, default_hfill_max);
|
||||
_nb_columns = std::min((size_t)w.ws_col, default_hfill_max);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -493,7 +503,7 @@ class clutchlog
|
|||
/** Style of the filling. */
|
||||
fmt _hfill_fmt;
|
||||
/** Maximum number of fill char. */
|
||||
unsigned short _hfill_max;
|
||||
size_t _hfill_max;
|
||||
#endif
|
||||
/** Standard output. */
|
||||
std::ostream* _out;
|
||||
|
|
@ -571,13 +581,13 @@ class clutchlog
|
|||
* This version accept style arguments as if they were passed to `clutchlog::fmt`.
|
||||
*/
|
||||
template<class ... FMT>
|
||||
void style(FMT... styles) { this->hfill_style(fmt(styles...)); }
|
||||
void hfill_style(FMT... styles) { this->hfill_style(fmt(styles...)); }
|
||||
//! Get the character for the stretching hfill marker.
|
||||
fmt hfill_style() const {return _hfill_fmt;}
|
||||
//! Set the maximum number of hfill characters. */
|
||||
void hfill_max(const size_t nmax) {_hfill_max = nmax;}
|
||||
//! Get the maximum number of hfill characters. */
|
||||
unsigned short hfill_max() {return _hfill_max;}
|
||||
size_t hfill_max() {return _hfill_max;}
|
||||
#endif
|
||||
|
||||
//! Set the log level (below which logs are not printed) with an identifier.
|
||||
|
|
@ -793,7 +803,7 @@ class clutchlog
|
|||
|
||||
//! Substitute all tags in the format string with the corresponding information and apply the style corresponding to the log level.
|
||||
std::string format(
|
||||
std::string format,
|
||||
std::string row,
|
||||
const std::string& what,
|
||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||
const std::string& name,
|
||||
|
|
@ -808,52 +818,65 @@ class clutchlog
|
|||
#endif
|
||||
) const
|
||||
{
|
||||
format = replace(format, "\\{msg\\}", what);
|
||||
format = replace(format, "\\{file\\}", file);
|
||||
format = replace(format, "\\{func\\}", func);
|
||||
format = replace(format, "\\{line\\}", line);
|
||||
row = replace(row, "\\{msg\\}", what);
|
||||
row = replace(row, "\\{file\\}", file);
|
||||
row = replace(row, "\\{func\\}", func);
|
||||
row = replace(row, "\\{line\\}", line);
|
||||
|
||||
format = replace(format, "\\{level\\}", _level_word.at(stage));
|
||||
row = replace(row, "\\{level\\}", _level_word.at(stage));
|
||||
std::string letter(1, _level_word.at(stage).at(0)); // char -> string
|
||||
format = replace(format, "\\{level_letter\\}", letter);
|
||||
row = replace(row, "\\{level_letter\\}", letter);
|
||||
|
||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||
format = replace(format, "\\{name\\}", name);
|
||||
format = replace(format, "\\{depth\\}", depth - _strip_calls);
|
||||
row = replace(row, "\\{name\\}", name);
|
||||
row = replace(row, "\\{depth\\}", depth - _strip_calls);
|
||||
|
||||
std::ostringstream chevrons;
|
||||
for(size_t i = _strip_calls; i < depth; ++i) {
|
||||
chevrons << _depth_mark;
|
||||
}
|
||||
format = replace(format, "\\{depth_marks\\}", chevrons.str());
|
||||
row = replace(row, "\\{depth_marks\\}", chevrons.str());
|
||||
#endif
|
||||
|
||||
row = replace(row, "\\{level_fmt\\}", _level_fmt.at(stage).str());
|
||||
|
||||
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
|
||||
// hfill is replaced last to allow for correct line width estimation.
|
||||
const std::string raw_row = replace(row, "\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]", "");
|
||||
const std::string hfill_tag = "{hfill}";
|
||||
const size_t hfill_pos = format.find(hfill_tag);
|
||||
const size_t hfill_pos = row.find(hfill_tag);
|
||||
const size_t raw_hfill_pos = raw_row.find(hfill_tag);
|
||||
const size_t nb_columns = std::min(_nb_columns, _hfill_max);
|
||||
if(hfill_pos != std::string::npos) {
|
||||
if(_nb_columns > 0) {
|
||||
const size_t left_len = hfill_pos;
|
||||
const size_t right_len = format.size() - hfill_pos - hfill_tag.size();
|
||||
if(right_len+left_len > _nb_columns) {
|
||||
// The right part would go over the terminal width: add a new line.
|
||||
const std::string hfill(std::max((size_t)0, _nb_columns-right_len), _hfill_char);
|
||||
assert(raw_hfill_pos != std::string::npos);
|
||||
if(nb_columns > 0) {
|
||||
const size_t left_len = raw_hfill_pos;
|
||||
const size_t right_len = raw_row.size() - raw_hfill_pos - hfill_tag.size();
|
||||
if(right_len+left_len > nb_columns) {
|
||||
// The right part would go over the terminal width: add a new row.
|
||||
const std::string hfill(std::max((size_t)0, nb_columns-right_len), _hfill_char);
|
||||
const std::string hfill_styled = _hfill_fmt(hfill);
|
||||
format = replace(format, "\\{hfill\\}", "\n"+hfill_styled);
|
||||
row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
|
||||
} else {
|
||||
// There is some space in between left and right parts.
|
||||
const std::string hfill(std::max((size_t)0, _nb_columns - (right_len+left_len)), _hfill_char);
|
||||
const std::string hfill(std::max((size_t)0, nb_columns - (right_len+left_len)), _hfill_char);
|
||||
const std::string hfill_styled = _hfill_fmt(hfill);
|
||||
format = replace(format, "\\{hfill\\}", hfill_styled);
|
||||
row = replace(row, "\\{hfill\\}", hfill_styled);
|
||||
}
|
||||
} else {
|
||||
// We don't know the terminal width.
|
||||
const std::string hfill(1, _hfill_char);
|
||||
const std::string hfill_styled = _hfill_fmt(hfill);
|
||||
format = replace(format, "\\{hfill\\}", hfill_styled);
|
||||
row = replace(row, "\\{hfill\\}", hfill_styled);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// We cannot know the terminal width.
|
||||
const std::string hfill(1, _hfill_char);
|
||||
const std::string hfill_styled = _hfill_fmt(hfill);
|
||||
row = replace(row, "\\{hfill\\}", hfill_styled);
|
||||
#endif
|
||||
return _level_fmt.at(stage)(format);
|
||||
return _level_fmt.at(stage)(row);
|
||||
}
|
||||
|
||||
//! Print a log message IF the location matches the given one.
|
||||
|
|
@ -1011,7 +1034,7 @@ class clutchlog
|
|||
void hfill_fmt(fmt) {}
|
||||
fmt hfill_fmt() const {}
|
||||
void hfill_max(const size_t) {}
|
||||
unsigned short hfill_max() {}
|
||||
size_t hfill_max() {}
|
||||
#endif
|
||||
|
||||
void threshold(level) {}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,42 @@ int main(const int argc, char* argv[])
|
|||
{
|
||||
auto& log = clutchlog::logger();
|
||||
|
||||
log.style(clutchlog::level::critical,
|
||||
clutchlog::fmt::fg::red);
|
||||
log.style(clutchlog::level::error,
|
||||
clutchlog::fmt::fg::red);
|
||||
log.style(clutchlog::level::warning,
|
||||
clutchlog::fmt::fg::magenta);
|
||||
log.style(clutchlog::level::progress,
|
||||
clutchlog::fmt::fg::yellow);
|
||||
log.style(clutchlog::level::note,
|
||||
clutchlog::fmt::fg::green);
|
||||
log.style(clutchlog::level::info,
|
||||
clutchlog::fmt::fg::magenta);
|
||||
log.style(clutchlog::level::debug,
|
||||
clutchlog::fmt::fg::cyan);
|
||||
log.style(clutchlog::level::xdebug,
|
||||
clutchlog::fmt::fg::blue);
|
||||
std::ostringstream format;
|
||||
clutchlog::fmt reset(clutchlog::fmt::typo::reset);
|
||||
clutchlog::fmt discreet(clutchlog::fmt::fg::black);
|
||||
clutchlog::fmt bold(clutchlog::fmt::typo::bold);
|
||||
format << "{level_fmt}"
|
||||
<< "{level_letter}:"
|
||||
<< "{depth_marks} "
|
||||
<< bold("{msg}")
|
||||
<< discreet(" {hfill} ")
|
||||
<< "{level_fmt}{func}"
|
||||
<< discreet(" @ ")
|
||||
<< "{level_fmt}{file}"
|
||||
<< reset << ":"
|
||||
<< "{level_fmt}{line}"
|
||||
<< "\n";
|
||||
log.format(format.str());
|
||||
|
||||
// log.hfill_max(100);
|
||||
log.out(std::clog);
|
||||
log.depth_mark("\t");
|
||||
log.format("[{name}] {level}: {depth_marks} {msg}\n");
|
||||
log.style(clutchlog::level::progress,clutchlog::fmt::fg::blue);
|
||||
log.depth_mark(">");
|
||||
log.threshold(clutchlog::level::warning);
|
||||
|
||||
if(argc <= 2) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue