diff --git a/README.md b/README.md index 639ab28..ef0ee3e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,14 @@ Clutchlog — versatile (de)clutchable logging - [Project page on Github](https://github.com/nojhan/clutchlog) - [Documentation](https://nojhan.github.io/clutchlog/) -![Clutchlog logo](https://raw.githubusercontent.com/nojhan/clutchlog/master/docs/clutchlog_logo.svg) +

+ +

+ [TOC] Features @@ -77,23 +84,6 @@ 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 ----- @@ -128,6 +118,23 @@ CLUTCHDUMP(debug, vec, "test_{n}.dat"); Note that if you pass a file name without the `{n}` tag, the file will be overwritten as is. +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`). + + Location filtering ------------------ @@ -234,7 +241,16 @@ and its default with the `CLUTCHLOG_DEFAULT_HFILL_MARK` macro: log.hfill_mark(CLUTCHLOG_DEFAULT_HFILL_MARK); // Defaults to '.'. ``` -Note: if the system detects no terminal, only a single fill character is inserted. +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). +```cpp +log.hfill_max(CLUTCHLOG_DEFAULT_HFILL_MAX); // Defaults to 300. +``` +Note: clutchlog will select the minimum between `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 +in any cases. ## Stack Depth @@ -306,6 +322,12 @@ 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`, +for example: +```cpp + log.hfill_style(clutchlog::fmt::fg::black); +``` + Disabled calls -------------- @@ -318,7 +340,7 @@ by setting the `WITH_CLUTCHLOG` preprocessor variable. When the `NDEBUG` preprocessor variable is set (e.g. in `Release` build), clutchlog will do its best to allow the compiler to optimize out any calls -for log levels that are under or equal to `progress`. +for log levels that are under `progress`. You can change this behavior at compile time by setting the `CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG` preprocessor variable diff --git a/clutchlog/clutchlog.h b/clutchlog/clutchlog.h index 134792a..ac3b639 100644 --- a/clutchlog/clutchlog.h +++ b/clutchlog/clutchlog.h @@ -1,6 +1,6 @@ -#ifndef __CLUTCHLOG_H__ -#define __CLUTCHLOG_H__ #pragma once +#ifndef CLUTCHLOG_H +#define CLUTCHLOG_H /** @file */ #include @@ -257,10 +257,23 @@ class clutchlog #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; + + + #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1 + #ifndef CLUTCHLOG_HFILL_MAX + #define CLUTCHLOG_HFILL_MAX 300 + #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; + + // NOTE: there is no CLUTCHLOG_HFILL_STYLE for defaulting, + // but you can still set `hfill_style(...)` on the logger singleton. /* @} */ public: + /** @name High-level API * @{ */ @@ -435,12 +448,16 @@ class clutchlog }), _format_log(clutchlog::default_format), _format_dump(clutchlog::dump_default_format), - _hfill_char(clutchlog::default_hfill_char), + #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL + _hfill_char(clutchlog::default_hfill_char), + _hfill_fmt(fmt::fg::none), + _hfill_max(clutchlog::default_hfill_max), + #endif _out(&std::clog), -#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 - _depth(std::numeric_limits::max() - _strip_calls), - _depth_mark(clutchlog::default_depth_mark), -#endif + #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + _depth(std::numeric_limits::max() - _strip_calls), + _depth_mark(clutchlog::default_depth_mark), + #endif _stage(level::error), _in_file(".*"), _in_func(".*"), @@ -452,8 +469,8 @@ class clutchlog } #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - _nb_columns = w.ws_col; + ioctl(STDERR_FILENO, TIOCGWINSZ, &w); + _nb_columns = std::min(w.ws_col, default_hfill_max); #endif } @@ -470,16 +487,22 @@ class clutchlog std::string _format_log; /** Current format of the file output. */ std::string _format_dump; - /** Character for filling. */ - char _hfill_char; + #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL + /** Character for filling. */ + char _hfill_char; + /** Style of the filling. */ + fmt _hfill_fmt; + /** Maximum number of fill char. */ + unsigned short _hfill_max; + #endif /** Standard output. */ std::ostream* _out; -#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 - /** Current stack depth (above which logs are not printed). */ - size_t _depth; - /** Current depth mark. */ - std::string _depth_mark; -#endif + #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + /** Current stack depth (above which logs are not printed). */ + size_t _depth; + /** Current depth mark. */ + std::string _depth_mark; + #endif /** Current log level. */ level _stage; /** Current file location filter. */ @@ -541,6 +564,20 @@ class clutchlog void hfill_mark(const char mark) {_hfill_char = mark;} //! Get the character for the stretching hfill marker. char hfill_mark() const {return _hfill_char;} + //! Set the style for the stretching hfill marker, with a `fmt` object. + void hfill_style(fmt style) {_hfill_fmt = style;} + /** Set the style for the stretching hfill marker. + * + * This version accept style arguments as if they were passed to `clutchlog::fmt`. + */ + template + void 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;} #endif //! Set the log level (below which logs are not printed) with an identifier. @@ -800,15 +837,19 @@ class clutchlog 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); - format = replace(format, "\\{hfill\\}", "\n"+hfill); + const std::string hfill_styled = _hfill_fmt(hfill); + format = replace(format, "\\{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); - format = replace(format, "\\{hfill\\}", hfill); + const std::string hfill_styled = _hfill_fmt(hfill); + format = replace(format, "\\{hfill\\}", hfill_styled); } } else { // We don't know the terminal width. - format = replace(format, "\\{hfill\\}", _hfill_char); + const std::string hfill(1, _hfill_char); + const std::string hfill_styled = _hfill_fmt(hfill); + format = replace(format, "\\{hfill\\}", hfill_styled); } } #endif @@ -967,12 +1008,16 @@ class clutchlog #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1 void hfill_mark(const char) {} char hfill_mark() const {} + void hfill_fmt(fmt) {} + fmt hfill_fmt() const {} + void hfill_max(const size_t) {} + unsigned short hfill_max() {} #endif void threshold(level) {} void threshold(const std::string&) {} level threshold() const {} - const std::map levels() const {}; + const std::map levels() const {} level level_of(const std::string) {} void file(std::string) {} @@ -988,6 +1033,8 @@ class clutchlog ) {} #pragma GCC diagnostic pop + template + void style(level, FMT...) {} void style(level, fmt) {} fmt style(level) const {} public: @@ -1042,4 +1089,4 @@ class clutchlog #pragma GCC diagnostic pop #endif // WITH_CLUTCHLOG -#endif // __CLUTCHLOG_H__ +#endif // CLUTCHLOG_H