feat: add the {hfill} format tag
and update the readme.
This commit is contained in:
parent
c6f2737527
commit
fc26a8af5a
2 changed files with 156 additions and 24 deletions
68
README.md
68
README.md
|
|
@ -4,6 +4,9 @@ Clutchlog — versatile (de)clutchable logging
|
||||||
***Clutchlog is a logging system that targets versatile debugging.***
|
***Clutchlog is a logging system that targets versatile debugging.***
|
||||||
***It allows to (de)clutch messages for a given: log level, source code location or call stack depth.***
|
***It allows to (de)clutch messages for a given: log level, source code location or call stack depth.***
|
||||||
|
|
||||||
|
- [Project page on Github](https://github.com/nojhan/clutchlog)
|
||||||
|
- [Documentation](https://nojhan.github.io/clutchlog/)
|
||||||
|
|
||||||

|

|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
|
|
@ -176,33 +179,66 @@ log.format("{msg}");
|
||||||
Available tags are:
|
Available tags are:
|
||||||
|
|
||||||
- `{msg}`: the logged message,
|
- `{msg}`: the logged message,
|
||||||
- `{name}`: the name of the current binary,
|
|
||||||
- `{level}`: the current log level (i.e. `Critical`, `Error`, `Warning`, `Progress`, `Note`, `Info`, `Debug` or `XDebug`),
|
- `{level}`: the current log level (i.e. `Critical`, `Error`, `Warning`, `Progress`, `Note`, `Info`, `Debug` or `XDebug`),
|
||||||
- `{level_letter}`: the first letter of the current log level,
|
- `{level_letter}`: the first letter of the current log level,
|
||||||
- `{file}`: the current file (absolute path),
|
- `{file}`: the current file (absolute path),
|
||||||
- `{func}`: the current function,
|
- `{func}`: the current function,
|
||||||
- `{line}`: the current line number,
|
- `{line}`: the current line number.
|
||||||
- `{depth}`: the current depth of the call stack,
|
|
||||||
- `{depth_marks}`: as many chevrons `>` as there is calls in the stack.
|
|
||||||
|
|
||||||
The default log format is `"[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"`,
|
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,
|
||||||
|
- `{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.
|
||||||
|
|
||||||
|
|
||||||
|
### Log Format
|
||||||
|
|
||||||
|
The default log format is `"[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\n"`,
|
||||||
it can be overriden at compile time by defining the `CLUTCHLOG_DEFAULT_FORMAT` macro.
|
it can be overriden at compile time by defining the `CLUTCHLOG_DEFAULT_FORMAT` macro.
|
||||||
|
|
||||||
The default format of the first line of comment added with the dump macro is
|
By default, and if `CLUTCHLOG_DEFAULT_FORMAT` is not defined,
|
||||||
|
clutchlog will not put the location-related tags in the message formats
|
||||||
|
(i.e. `{name}`, `{func}`, and `{line}`) when not in Debug builds.
|
||||||
|
|
||||||
|
|
||||||
|
### Dump Format
|
||||||
|
|
||||||
|
The default format of the first line of comment added with the dump macro is
|
||||||
`"# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"`.
|
`"# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"`.
|
||||||
It can be edited with the `format_comment` method.
|
It can be edited with the `format_comment` method.
|
||||||
If it is set to an empty string, then no comment line is added.
|
If it is set to an empty string, then no comment line is added.
|
||||||
The default can be modified at compile time with `CLUTCHDUMP_DEFAULT_FORMAT`.
|
The default can be modified at compile time with `CLUTCHDUMP_DEFAULT_FORMAT`.
|
||||||
|
|
||||||
By default, the separator between items in the container is a new line.
|
By default, the separator between items in the container is a new line.
|
||||||
To change this behaviour, you can change `CLUTCHDUMP_DEFAULT_SEP` or
|
To change this behaviour, you can change `CLUTCHDUMP_DEFAULT_SEP` or
|
||||||
call the low-level `dump` method.
|
call the low-level `dump` method.
|
||||||
|
|
||||||
|
By default, and if `CLUTCHDUMP_DEFAULT_FORMAT` is not defined,
|
||||||
|
clutchlog will not put the location-related tags in the message formats
|
||||||
|
(i.e. `{file}` and `{line}`) when not in Debug builds.
|
||||||
|
|
||||||
|
|
||||||
|
### 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 `depth_mark` method,
|
||||||
and its default with the `CLUTCHLOG_DEFAULT_DEPTH_MARK` macro:
|
and its default with the `CLUTCHLOG_DEFAULT_DEPTH_MARK` macro:
|
||||||
```cpp
|
```cpp
|
||||||
log.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); // Defaults to ">".
|
log.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); // Defaults to ">".
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The character used with the `{hfill}` tag can be configured wth the `hfill_mark` method,
|
||||||
|
and its default with the `CLUTCHLOG_DEFAULT_HFILL_MARK` macro:
|
||||||
|
```cpp
|
||||||
|
log.hfill_mark(CLUTCHLOG_DEFAULT_HFILL_MARK); // Defaults to '.'.
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: if the system detects no terminal, only a single fill character is inserted.
|
||||||
|
|
||||||
|
|
||||||
|
## Stack Depth
|
||||||
|
|
||||||
By default, clutchlog removes 5 levels of the calls stack, so that your `main`
|
By default, clutchlog removes 5 levels of the calls stack, so that your `main`
|
||||||
entrypoint corresponds to a depth of zero.
|
entrypoint corresponds to a depth of zero.
|
||||||
You can change this behaviour by defining the `CLUTCHLOG_STRIP_CALLS` macro.
|
You can change this behaviour by defining the `CLUTCHLOG_STRIP_CALLS` macro.
|
||||||
|
|
@ -362,7 +398,7 @@ Limitations
|
||||||
|
|
||||||
### System-dependent stack depth
|
### System-dependent stack depth
|
||||||
|
|
||||||
Because the call stack depth and program name access are system-dependent,
|
Because access to the call stack depth and program name are system-dependent,
|
||||||
the features relying on the depth of the call stack and the display of the program name
|
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:
|
are only available for operating systems having the following headers:
|
||||||
`execinfo.h`, `stdlib.h` and `libgen.h` (so far, tested with Linux).
|
`execinfo.h`, `stdlib.h` and `libgen.h` (so far, tested with Linux).
|
||||||
|
|
@ -377,6 +413,22 @@ You can make portable code using something like:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### System-dependent horizontal fill
|
||||||
|
|
||||||
|
Because access to the current terminal width is system-dependent,
|
||||||
|
the `{hfill}` format tag feature is only available for operating systems having the following headers:
|
||||||
|
`sys/ioctl.h`, `stdio.h` and `unistd.h` (so far, tested with Linux).
|
||||||
|
|
||||||
|
Clutchlog sets the `CLUTCHLOG_HAVE_UNIX_SYSIOCTL` to 1 if the headers are
|
||||||
|
available, and to 0 if they are not.
|
||||||
|
You can make portable code using something like:
|
||||||
|
```cpp
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
|
||||||
|
log.hfill_mark( '_' );
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
Some colors/styles may not be supported by some exotic terminal emulators.
|
Some colors/styles may not be supported by some exotic terminal emulators.
|
||||||
|
|
@ -388,7 +440,7 @@ You may need to indicate `-std=c++17 -lstdc++fs` to some compilers.
|
||||||
### Variable names within the CLUTCHLOG macro
|
### Variable names within the CLUTCHLOG macro
|
||||||
|
|
||||||
Calling the `CLUTCHLOG` macro with a message using a variable named `clutchlog__msg` will end in
|
Calling the `CLUTCHLOG` macro with a message using a variable named `clutchlog__msg` will end in
|
||||||
an error. Avoid this kind of naming for the logger singleton, also.
|
an error.
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@
|
||||||
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
|
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<sys/ioctl.h>) && __has_include(<stdio.h>) && __has_include(<unistd.h>)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 1
|
||||||
|
#else
|
||||||
|
#define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Enable by default in Debug builds.
|
* Enable by default in Debug builds.
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
@ -171,33 +181,52 @@ class clutchlog
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
||||||
//! Compile-time default format of the messages (debug mode: with absolute location).
|
//! Compile-time default format of the messages (debug mode: with absolute location).
|
||||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 // Enables: name, depth and depth_marks
|
||||||
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1 // Enables: hfill
|
||||||
|
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\n"
|
||||||
|
#else
|
||||||
|
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
|
||||||
|
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg} {hfill} {func} @ {file}:{line}\n"
|
||||||
|
#else
|
||||||
|
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
||||||
//! Compile-time default format of the messages (debug mode: with absolute location).
|
//! Compile-time default format of the messages (non-debug mode: without absolute location).
|
||||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||||
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\n"
|
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter}:{depth_marks} {msg} {hfill} {func}\n"
|
||||||
#else
|
#else
|
||||||
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\n"
|
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func}\n"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
//! Default format of the messages.
|
//! Default format of the messages.
|
||||||
static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
|
static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
|
||||||
|
|
||||||
#ifndef CLUTCHDUMP_DEFAULT_FORMAT
|
#ifndef NDEBUG
|
||||||
//! Compile-time default format of the comment line in file dump.
|
#ifndef CLUTCHDUMP_DEFAULT_FORMAT
|
||||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
//! Compile-time default format of the comment line in file dump.
|
||||||
#define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
|
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||||
#else
|
#define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
|
||||||
#define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
|
#else
|
||||||
#endif
|
#define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
|
||||||
#endif // CLUTCHDUMP_DEFAULT_FORMAT
|
#endif
|
||||||
|
#endif // CLUTCHDUMP_DEFAULT_FORMAT
|
||||||
|
#else
|
||||||
|
#ifndef CLUTCHDUMP_DEFAULT_FORMAT
|
||||||
|
//! Compile-time 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})"
|
||||||
|
#else
|
||||||
|
#define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func}"
|
||||||
|
#endif
|
||||||
|
#endif // CLUTCHDUMP_DEFAULT_FORMAT
|
||||||
|
#endif
|
||||||
//! Default format of the comment line in file dump.
|
//! Default format of the comment line in file dump.
|
||||||
static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
|
static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
|
||||||
|
|
||||||
|
|
@ -221,6 +250,13 @@ class clutchlog
|
||||||
#endif // CLUTCHLOG_STRIP_CALLS
|
#endif // CLUTCHLOG_STRIP_CALLS
|
||||||
//! Number of call stack levels to remove from depth display by default.
|
//! Number of call stack levels to remove from depth display by default.
|
||||||
static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
|
static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
|
||||||
|
|
||||||
|
#ifndef CLUTCHLOG_HFILL_MARK
|
||||||
|
//! Character used as a filling for right-align the right part of messages with "{hfill}".
|
||||||
|
#define CLUTCHLOG_HFILL_MARK '.'
|
||||||
|
#endif // CLUTCHLOG_HFILL_MARK
|
||||||
|
//! Default character used as a filling for right-align the right part of messages with "{hfill}".
|
||||||
|
static inline char default_hfill_char = CLUTCHLOG_HFILL_MARK;
|
||||||
/* @} */
|
/* @} */
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -399,6 +435,7 @@ class clutchlog
|
||||||
}),
|
}),
|
||||||
_format_log(clutchlog::default_format),
|
_format_log(clutchlog::default_format),
|
||||||
_format_dump(clutchlog::dump_default_format),
|
_format_dump(clutchlog::dump_default_format),
|
||||||
|
_hfill_char(clutchlog::default_hfill_char),
|
||||||
_out(&std::clog),
|
_out(&std::clog),
|
||||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||||
_depth(std::numeric_limits<size_t>::max() - _strip_calls),
|
_depth(std::numeric_limits<size_t>::max() - _strip_calls),
|
||||||
|
|
@ -413,6 +450,11 @@ class clutchlog
|
||||||
for(auto& lw : _level_word) {
|
for(auto& lw : _level_word) {
|
||||||
_word_level[lw.second] = lw.first;
|
_word_level[lw.second] = lw.first;
|
||||||
}
|
}
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
|
||||||
|
struct winsize w;
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
_nb_columns = w.ws_col;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -428,6 +470,8 @@ class clutchlog
|
||||||
std::string _format_log;
|
std::string _format_log;
|
||||||
/** Current format of the file output. */
|
/** Current format of the file output. */
|
||||||
std::string _format_dump;
|
std::string _format_dump;
|
||||||
|
/** Character for filling. */
|
||||||
|
const char _hfill_char;
|
||||||
/** Standard output. */
|
/** Standard output. */
|
||||||
std::ostream* _out;
|
std::ostream* _out;
|
||||||
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
|
||||||
|
|
@ -449,6 +493,11 @@ class clutchlog
|
||||||
/** Maximum buffer size for backtrace message. */
|
/** Maximum buffer size for backtrace message. */
|
||||||
static const size_t _max_buffer = 4096;
|
static const size_t _max_buffer = 4096;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
|
||||||
|
/** Current terminal size (for right-alignment). */
|
||||||
|
size_t _nb_columns;
|
||||||
|
#endif
|
||||||
/** @}*/
|
/** @}*/
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -478,10 +527,16 @@ class clutchlog
|
||||||
size_t depth() const {return _depth;}
|
size_t depth() const {return _depth;}
|
||||||
|
|
||||||
//! Set the string mark with which stack depth is indicated.
|
//! Set the string mark with which stack depth is indicated.
|
||||||
void depth_mark(std::string mark) {_depth_mark = mark;}
|
void depth_mark(const std::string mark) {_depth_mark = mark;}
|
||||||
//! Get the string mark with which stack depth is indicated.
|
//! Get the string mark with which stack depth is indicated.
|
||||||
std::string depth_mark() const {return _depth_mark;}
|
std::string depth_mark() const {return _depth_mark;}
|
||||||
#endif
|
#endif
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
|
||||||
|
//! Set the character for the stretching hfill marker.
|
||||||
|
void hfill_mark(const char mark) {_hfill_char = mark;}
|
||||||
|
//! Get the character for the stretching hfill marker.
|
||||||
|
char hfill_mark() const {return _hfill_char;}
|
||||||
|
#endif
|
||||||
|
|
||||||
//! Set the log level (below which logs are not printed) with an identifier.
|
//! 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;}
|
||||||
|
|
@ -730,7 +785,28 @@ class clutchlog
|
||||||
}
|
}
|
||||||
format = replace(format, "\\{depth_marks\\}", chevrons.str());
|
format = replace(format, "\\{depth_marks\\}", chevrons.str());
|
||||||
#endif
|
#endif
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
|
||||||
|
const std::string hfill_tag = "{hfill}";
|
||||||
|
const size_t hfill_pos = format.find(hfill_tag);
|
||||||
|
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(0, _nb_columns-right_len), _hfill_char);
|
||||||
|
format = replace(format, "\\{hfill\\}", "\n"+hfill);
|
||||||
|
} else {
|
||||||
|
// There is some space in between left and right parts.
|
||||||
|
const std::string hfill(std::max(0, _nb_columns - (right_len+left_len)), _hfill_char);
|
||||||
|
format = replace(format, "\\{hfill\\}", hfill);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We don't know the terminal width.
|
||||||
|
format = replace(format, "\\{hfill\\}", _hfill_char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return _level_fmt.at(stage)(format);
|
return _level_fmt.at(stage)(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -878,9 +954,13 @@ class clutchlog
|
||||||
void depth(size_t) {}
|
void depth(size_t) {}
|
||||||
size_t depth() const {}
|
size_t depth() const {}
|
||||||
|
|
||||||
void depth_mark(std::string) {}
|
void depth_mark(const std::string) {}
|
||||||
std::string depth_mark() const {}
|
std::string depth_mark() const {}
|
||||||
#endif
|
#endif
|
||||||
|
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
|
||||||
|
void hfill_mark(const char) {}
|
||||||
|
char hfill_mark() const {}
|
||||||
|
#endif
|
||||||
|
|
||||||
void threshold(level) {}
|
void threshold(level) {}
|
||||||
void threshold(const std::string&) {}
|
void threshold(const std::string&) {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue