clutchlog.h
Go to the documentation of this file.
#pragma once
#ifndef CLUTCHLOG_H
#define CLUTCHLOG_H
#include <ciso646>
#ifdef FSEXPERIMENTAL
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#include <filesystem>
namespace fs = std::filesystem;
#endif
#include <iostream>
#include <sstream>
#include <fstream>
#include <cassert>
#include <cstdlib>
#include <string>
#include <limits>
#include <regex>
#include <map>
#if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
#include <execinfo.h> // execinfo
#include <stdlib.h> // getenv
#include <libgen.h> // basename
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
#else
#define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
#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.
**********************************************************************/
#ifndef WITH_CLUTCHLOG
#ifndef NDEBUG
#define WITH_CLUTCHLOG
#endif
#endif
/**********************************************************************
* Macros definitions
**********************************************************************/
#ifdef WITH_CLUTCHLOG
#ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
#define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
#endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
#define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
#ifndef NDEBUG
#define CLUTCHLOG( LEVEL, WHAT ) do { \
auto& clutchlog__logger = clutchlog::logger(); \
std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
} while(0)
#else // not Debug build.
#define CLUTCHLOG( LEVEL, WHAT ) do { \
if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
auto& clutchlog__logger = clutchlog::logger(); \
std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC); \
} \
} while(0)
#endif // NDEBUG
#ifndef NDEBUG
#define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
} while(0)
#else // not Debug build.
#define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
} \
} while(0)
#endif // NDEBUG
#ifndef NDEBUG
#define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
if(clutchlog__scope.matches) { \
FUNC(__VA_ARGS__); \
} \
} while(0)
#else // not Debug build.
#define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
if(clutchlog__scope.matches) { \
FUNC(__VA_ARGS__); \
} \
} \
} while(0)
#endif // NDEBUG
#ifndef NDEBUG
#define CLUTCHCODE( LEVEL, ... ) do { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
if(clutchlog__scope.matches) { \
__VA_ARGS__ \
} \
} while(0)
#else // not Debug build.
#define CLUTCHCODE( LEVEL, CODE ) do { \
if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
auto& clutchlog__logger = clutchlog::logger(); \
clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
if(clutchlog__scope.matches) { \
CODE \
} \
} \
} while(0)
#endif // NDEBUG
#else // not WITH_CLUTCHLOG
// Disabled macros can still be called in Release builds.
#define CLUTCHLOG( LEVEL, WHAT ) do {/*nothing*/} while(0)
#define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {/*nothing*/} while(0)
#define CLUTCHFUNC( LEVEL, FUNC, ... ) do {/*nothing*/} while(0)
#define CLUTCHCODE( LEVEL, CODE ) do {/*nothing*/} while(0)
#endif // WITH_CLUTCHLOG
/**********************************************************************
* Implementation
**********************************************************************/
#ifdef WITH_CLUTCHLOG
class clutchlog
{
protected:
#ifndef NDEBUG
#ifndef CLUTCHLOG_DEFAULT_FORMAT
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 // Enables: name, depth and depth_marks
#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
#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
#else
#ifndef CLUTCHLOG_DEFAULT_FORMAT
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func}\n"
#else
#define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func}\n"
#endif
#endif
#endif
static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
#ifndef NDEBUG
#ifndef CLUTCHDUMP_DEFAULT_FORMAT
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
#define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
#else
#define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
#endif
#endif // CLUTCHDUMP_DEFAULT_FORMAT
#else
#ifndef CLUTCHDUMP_DEFAULT_FORMAT
#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
static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
#ifndef CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP "\n"
#endif // CLUTCHDUMP_DEFAULT_SEP
static inline std::string dump_default_sep = CLUTCHDUMP_DEFAULT_SEP;
#ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
#endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
static inline std::string default_depth_mark = CLUTCHLOG_DEFAULT_DEPTH_MARK;
#ifndef CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS 5
#endif // CLUTCHLOG_STRIP_CALLS
static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
#ifndef CLUTCHLOG_DEFAULT_HFILL_MARK
#define CLUTCHLOG_DEFAULT_HFILL_MARK '.'
#endif // CLUTCHLOG_DEFAULT_HFILL_MARK
static inline char default_hfill_char = CLUTCHLOG_DEFAULT_HFILL_MARK;
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
#ifndef CLUTCHLOG_DEFAULT_HFILL_MAX
#define CLUTCHLOG_DEFAULT_HFILL_MAX 300
#endif
#ifndef CLUTCHLOG_DEFAULT_HFILL_MIN
#define CLUTCHLOG_DEFAULT_HFILL_MIN 150
#endif
#endif
static inline size_t default_hfill_max = CLUTCHLOG_DEFAULT_HFILL_MAX;
static inline size_t default_hfill_min = CLUTCHLOG_DEFAULT_HFILL_MIN;
// NOTE: there is no CLUTCHLOG_HFILL_STYLE for defaulting,
// but you can still set `hfill_style(...)` on the logger singleton.
/* @} DefaultConfig */
/* @} */
public:
static clutchlog& logger()
{
static clutchlog instance;
return instance;
}
enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
class fmt {
public:
enum class ansi {
colors_16 = -1, // Not supposed to be casted.
colors_256 = 5, // Casted as short in color::operator<<.
colors_16M = 2 // Casted as short in color::operator<<
} mode;
enum class typo {
reset = 0,
bold = 1,
underline = 4,
inverse = 7,
none = -1
} style;
enum class fg {
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
white = 37,
bright_black = 90,
bright_red = 91,
bright_green = 92,
bright_yellow = 93,
bright_blue = 94,
bright_magenta = 95,
bright_cyan = 96,
bright_white = 97,
none = -1
} fore;
enum class bg {
black = 40,
red = 41,
green = 42,
yellow = 43,
blue = 44,
magenta = 45,
cyan = 46,
white = 47,
bright_black = 100,
bright_red = 101,
bright_green = 102,
bright_yellow = 103,
bright_blue = 104,
bright_magenta = 105,
bright_cyan = 106,
bright_white = 107,
none = -1
} back;
protected:
friend std::ostream& operator<<(std::ostream& os, const std::tuple<fg,bg,typo>& fbs)
{
auto [f,b,s] = fbs;
std::vector<short> codes; codes.reserve(3);
if(f != fg::none) { codes.push_back(static_cast<short>(f));}
if(b != bg::none) { codes.push_back(static_cast<short>(b));}
if(s != typo::none) { codes.push_back(static_cast<short>(s));}
if(codes.size() == 0) {
return os;
} else {
os << "\033[";
os << codes[0];
for(size_t i=1; i < codes.size(); ++i) {
os << ";" << codes[i];
}
os << "m";
}
return os;
}
friend std::ostream& operator<<(std::ostream& os, const typo& s)
{
if(s != typo::none) {
os << "\033[" << static_cast<short>(s) << "m";
}
return os;
}
protected:
struct color {
ansi mode; // Not const to allow for the implicit copy assignemnt operator.
enum class ground { // idem.
fore = 38,
back = 48
} type;
color(ansi a, ground g) : mode(a), type(g) {}
virtual bool is_set() const = 0;
virtual std::ostream& print_on( std::ostream& os) const = 0;
friend std::ostream& operator<<(std::ostream& os, const color& c)
{
if(c.is_set()) {
os << "\033[" << static_cast<short>(c.type) << ";" << static_cast<short>(c.mode) << ";";
c.print_on(os);
os << "m";
}
return os;
}
};
// There is no color_16 because it would be the same as color_256, only with different indices,
// hence making it more complicated for the user to select the right constructor.
// Here, we just use enum for 16 colors, and indices for 256 colors.
struct color_256 : public color {
short index;
color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {assert(-1 <= i and i <= 255);}
bool is_set() const {return index > -1;}
std::ostream& print_on( std::ostream& os) const
{
os << index;
return os;
}
};
struct fg_256 : public color_256 {
fg_256() : color_256(ground::fore) {}
fg_256(const short f) : color_256(ground::fore, f) {}
fg_256(const fg&) : color_256(ground::fore, -1) {}
} fore_256;
struct bg_256 : public color_256 {
bg_256() : color_256(ground::back) {}
bg_256(const short b) : color_256(ground::back, b) {}
bg_256(const bg&) : color_256(ground::back, -1) {}
} back_256;
struct color_16M : public color {
short red, green, blue;
color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
color_16M(ground t, short r, short g, short b)
: color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
color_16M(ground t, const std::string& srgb) : color(ansi::colors_16M, t)
{
assert(srgb.size() == 7);
if(srgb.size() != 7) {
red = -1;
green = -1;
blue = -1;
} else {
char i = 0;
if(srgb.at(0) == '#') {
i = 1;
}
std::istringstream(srgb.substr(0+i,2)) >> std::hex >> red;
std::istringstream(srgb.substr(2+i,2)) >> std::hex >> green;
std::istringstream(srgb.substr(4+i,2)) >> std::hex >> blue;
}
assert(-1 <= red and red <= 255);
assert(-1 <= green and green <= 255);
assert(-1 <= blue and blue <= 255);
}
bool is_set() const {return red > -1 and green > -1 and blue > -1;}
std::ostream& print_on( std::ostream& os) const
{
os << red << ";" << green << ";" << blue;
return os;
}
};
struct fg_16M : public color_16M {
fg_16M() : color_16M(ground::fore) {}
fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
} fore_16M;
struct bg_16M : public color_16M {
bg_16M() : color_16M(ground::back) {}
bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
} back_16M;
public:
fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
fmt(const short fr, const short fg, const short fb,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
fmt(fg,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
fmt(const short fr, const short fg, const short fb,
bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const short fr, const short fg, const short fb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const std::string& f, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
fmt(fg, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
fmt(const std::string& f, bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
fmt(const std::string& f, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
protected:
std::ostream& print_on( std::ostream& os) const
{
if(mode == ansi::colors_16) {
// Print all in a single escape.
os << std::make_tuple(fore,back,style);
} else {
// 256 or 16M: always print separated escapes for foreground/background.
if(mode == ansi::colors_256) {
os << fore_256;
os << back_256;
} else if(mode == ansi::colors_16M) {
os << fore_16M;
os << back_16M;
}
// In any case, print the style separately.
os << style;
}
return os;
}
public:
friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
{
return fmt.print_on(os);
}
std::string operator()( const std::string& msg ) const
{
std::ostringstream os;
this->print_on(os);
fmt reset(fmt::typo::reset);
os << msg;
reset.print_on(os);
return os.str();
}
std::string str() const
{
std::ostringstream os;
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
public:
clutchlog(clutchlog const&) = delete;
void operator=(clutchlog const&) = delete;
private:
clutchlog() :
// system, main, log
_strip_calls(clutchlog::default_strip_calls),
_level_word({
{level::critical,"Critical"},
{level::error ,"Error"},
{level::warning ,"Warning"},
{level::progress,"Progress"},
{level::note ,"Note"},
{level::info ,"Info"},
{level::debug ,"Debug"},
{level::xdebug ,"XDebug"}
}),
_level_short({
{level::critical, "Crit"},
{level::error , "Erro"},
{level::warning , "Warn"},
{level::progress, "Prog"},
{level::note , "Note"},
{level::info , "Info"},
{level::debug , "Dbug"},
{level::xdebug , "XDbg"}
}),
_level_fmt({
{level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
{level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
{level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
{level::progress,fmt()},
{level::note ,fmt()},
{level::info ,fmt()},
{level::debug ,fmt()},
{level::xdebug ,fmt()}
}),
_format_log(clutchlog::default_format),
_format_dump(clutchlog::dump_default_format),
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
_hfill_char(clutchlog::default_hfill_char),
_hfill_fmt(fmt::fg::none),
_hfill_max(clutchlog::default_hfill_max),
_hfill_min(clutchlog::default_hfill_min),
#endif
_out(&std::clog),
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
_depth(std::numeric_limits<size_t>::max() - _strip_calls),
_depth_mark(clutchlog::default_depth_mark),
#endif
_stage(level::error),
_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) {
_word_level[lw.second] = lw.first;
}
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
struct winsize w;
ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
_nb_columns = std::max(std::min((size_t)w.ws_col, default_hfill_max), default_hfill_min);
#endif
}
protected:
size_t _strip_calls;
const std::map<level,std::string> _level_word;
std::map<std::string,level> _word_level;
std::map<level,std::string> _level_short;
std::map<level,fmt> _level_fmt;
std::string _format_log;
std::string _format_dump;
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
char _hfill_char;
fmt _hfill_fmt;
size_t _hfill_max;
size_t _hfill_min;
#endif
std::ostream* _out;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
size_t _depth;
std::string _depth_mark;
#endif
level _stage;
std::regex _in_file;
std::regex _in_func;
std::regex _in_line;
std::vector<fmt> _filehash_fmts;
std::vector<fmt> _funchash_fmts;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
static const size_t _max_buffer = 4096;
std::vector<fmt> _depth_fmts;
#endif
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
size_t _nb_columns;
#endif
public:
void format(const std::string& format) {_format_log = format;}
std::string format() const {return _format_log;}
void format_comment(const std::string& format) {_format_dump = format;}
std::string format_comment() const {return _format_dump;}
void out(std::ostream& out) {_out = &out;}
std::ostream& out() {return *_out;}
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
void depth(size_t d) {_depth = d;}
size_t depth() const {return _depth;}
void depth_mark(const std::string mark) {_depth_mark = mark;}
std::string depth_mark() const {return _depth_mark;}
void strip_calls(const size_t n) {_strip_calls = n;}
size_t strip_calls() const {return _strip_calls;}
#endif
#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
void hfill_mark(const char mark) {_hfill_char = mark;}
char hfill_mark() const {return _hfill_char;}
void hfill_style(fmt style) {_hfill_fmt = style;}
template<class ... FMT>
void hfill_style(FMT... styles) { this->hfill_style(fmt(styles...)); }
fmt hfill_style() const {return _hfill_fmt;}
void hfill_max(const size_t nmax) {_hfill_max = nmax;}
size_t hfill_max() {return _hfill_max;}
void hfill_min(const size_t nmin) {_hfill_min = nmin;}
size_t hfill_min() {return _hfill_min;}
#endif
void filehash_styles(std::vector<fmt> styles) {_filehash_fmts = styles;}
void funchash_styles(std::vector<fmt> styles) {_funchash_fmts = styles;}
void depth_styles(std::vector<fmt> styles) {_depth_fmts = styles;}
void threshold(level l) {_stage = l;}
void threshold(const std::string& l) {_stage = this->level_of(l);}
level threshold() const {return _stage;}
const std::map<std::string,level>& levels() const { return _word_level;}
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");
}
}
void file(std::string file) {_in_file = file;}
void func(std::string func) {_in_func = func;}
void line(std::string line) {_in_line = line;}
void location(
const std::string& in_file,
const std::string& in_function=".*",
const std::string& in_line=".*"
)
{
file(in_file);
func(in_function);
line(in_line);
}
template<class ... FMT>
void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
fmt style(level stage) const { return _level_fmt.at(stage); }
public:
struct scope_t {
bool matches;
level stage;
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
size_t depth;
#endif
bool there;
scope_t() :
matches(false),
stage(level::xdebug),
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
depth(0),
#endif
there(false)
{}
}; // scope_t
scope_t locate(
const level& stage,
const std::string& file,
const std::string& func,
const size_t line
) const
{
scope_t scope; // False scope by default.
/***** Log level stage *****/
// Test stage first, because it's fastest.
scope.stage = stage;
if(not (scope.stage <= _stage)) {
// Bypass useless computations if no match
// because of the stage.
return scope;
}
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
/***** Stack depth *****/
// Backtrace in second, quite fast.
size_t stack_depth;
void *buffer[_max_buffer];
stack_depth = backtrace(buffer, _max_buffer);
scope.depth = stack_depth;
if(not (scope.depth <= _depth + _strip_calls)) {
// Bypass if no match.
return scope;
}
#endif
/***** Location *****/
// Location last, slowest.
std::ostringstream sline; sline << line;
scope.there =
std::regex_search(file, _in_file)
and std::regex_search(func, _in_func)
and std::regex_search(sline.str(), _in_line);
// No need to retest stage and depth, which are true here.
scope.matches = scope.there;
return scope;
} // locate
std::string replace(
const std::string& form,
const std::string& mark,
const std::string& tag
) const
{
// Useless debug code, unless something fancy would be done with name tags.
// std::regex re;
// try {
// re = std::regex(mark);
//
// } catch(const std::regex_error& e) {
// std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
// switch(e.code()) {
// case std::regex_constants::error_collate:
// std::cerr << "the expression contains an invalid collating element name";
// break;
// case std::regex_constants::error_ctype:
// std::cerr << "the expression contains an invalid character class name";
// break;
// case std::regex_constants::error_escape:
// std::cerr << "the expression contains an invalid escaped character or a trailing escape";
// break;
// case std::regex_constants::error_backref:
// std::cerr << "the expression contains an invalid back reference";
// break;
// case std::regex_constants::error_brack:
// std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
// break;
// case std::regex_constants::error_paren:
// std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
// break;
// case std::regex_constants::error_brace:
// std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
// break;
// case std::regex_constants::error_badbrace:
// std::cerr << "the expression contains an invalid range in a {} expression";
// break;
// case std::regex_constants::error_range:
// std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
// break;
// case std::regex_constants::error_space:
// std::cerr << "there was not enough memory to convert the expression into a finite state machine";
// break;
// case std::regex_constants::error_badrepeat:
// std::cerr << "one of *?+{ was not preceded by a valid regular expression";
// break;
// case std::regex_constants::error_complexity:
// std::cerr << "the complexity of an attempted match exceeded a predefined level";
// break;
// case std::regex_constants::error_stack:
// std::cerr << "there was not enough memory to perform a match";
// break;
// default:
// std::cerr << "unknown error";
// }
// std::cerr << std::endl;
// throw;
// } // catch
const std::regex re(mark);
return std::regex_replace(form, re, tag);
}
std::string replace(
const std::string& form,
const std::string& mark,
const size_t tag
) const
{
std::ostringstream stag; stag << tag;
return replace(form, mark, stag.str());
}
std::string format(
std::string row,
const std::string& what,
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
const std::string& name,
#endif
const level& stage,
const std::string& file,
const std::string& func,
const size_t line
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
,
const size_t depth
#endif
) const
{
row = replace(row, "\\{msg\\}", what);
row = replace(row, "\\{file\\}", file);
row = replace(row, "\\{func\\}", func);
row = replace(row, "\\{line\\}", line);
row = replace(row, "\\{level\\}", _level_word.at(stage));
std::string letter(1, _level_word.at(stage).at(0)); // char -> string
row = replace(row, "\\{level_letter\\}", letter);
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\\}", actual_depth);
std::ostringstream chevrons;
for(size_t i = _strip_calls; i < depth; ++i) {
chevrons << _depth_mark;
}
row = replace(row, "\\{depth_marks\\}", chevrons.str());
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.
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 = row.find(hfill_tag);
const size_t raw_hfill_pos = raw_row.find(hfill_tag);
const size_t nb_columns = std::max(std::min((size_t)_nb_columns, _hfill_max), _hfill_min);
if(hfill_pos != std::string::npos) {
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.
if(right_len < nb_columns) {
// There is room for the right part on a new line.
const std::string hfill(std::max((size_t)0, nb_columns-right_len), _hfill_char);
const std::string hfill_styled = _hfill_fmt(hfill);
row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
} else {
// Right part still goes over columns: let it go.
const std::string hfill(1, _hfill_char);
const std::string hfill_styled = _hfill_fmt(hfill);
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_styled = _hfill_fmt(hfill);
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);
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)(row);
}
void log(
const level& stage,
const std::string& what,
const std::string& file, const std::string& func, size_t line
) const
{
scope_t scope = locate(stage, file, func, line);
if(scope.matches) {
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
*_out << format(_format_log, what, basename(getenv("_")),
stage, file, func,
line, scope.depth );
#else
*_out << format(_format_log, what,
stage, file, func,
line );
#endif
_out->flush();
} // if scopes.matches
}
template<class In>
void dump(
const level& stage,
const In container_begin, const In container_end,
const std::string& file, const std::string& func, size_t line,
const std::string& filename_template = "dump_{n}.dat",
const std::string sep = dump_default_sep
) const
{
scope_t scope = locate(stage, file, func, line);
if(scope.matches) {
const std::string tag = "\\{n\\}";
const std::regex re(tag);
std::string outfile = "";
// If the file name template has the {n} tag.
if(std::regex_search(filename_template, re)) {
// Increment n until a free one is found.
size_t n = 0;
do {
outfile = replace(filename_template, tag, n);
n++;
} while( fs::exists( outfile ) );
} else {
// Use the parameter as is.
outfile = filename_template;
}
std::ofstream fd(outfile);
if(_format_dump.size() > 0) {
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
fd << format(_format_dump, "", basename(getenv("_")),
stage, file, func,
line, scope.depth );
#else
fd << format(_format_dump, "",
stage, file, func,
line );
#endif
fd << sep; // sep after comment line.
}
std::copy(container_begin, container_end,
std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
fd.close();
} // if scopes.matches
}
};
#else // not WITH_CLUTCHLOG
/**********************************************************************
* Fake implementation
**********************************************************************/
// Equivalent class with empty methods, will be optimized out
// while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
class clutchlog
{
public:
static clutchlog& logger() {}
enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
class fmt {
public:
enum class ansi { colors_16, colors_256, colors_16M} mode;
enum class typo { reset, bold, underline, inverse, none} style;
enum class fg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none} fore;
enum class bg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none } back;
protected:
friend std::ostream& operator<<(std::ostream&, const std::tuple<fg,bg,typo>&) {}
friend std::ostream& operator<<(std::ostream&, const typo&) {}
protected:
struct color {
ansi mode;
enum class ground { fore, back } type;
color(ansi a, ground g) : mode(a), type(g) {}
virtual bool is_set() const = 0;
virtual std::ostream& print_on( std::ostream&) const = 0;
friend std::ostream& operator<<(std::ostream&, const color&) {}
};
struct color_256 : public color {
short index;
color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {}
bool is_set() const {}
std::ostream& print_on( std::ostream&) const {}
};
struct fg_256 : public color_256 {
fg_256() : color_256(ground::fore) {}
fg_256(const short f) : color_256(ground::fore, f) {}
fg_256(const fg&) : color_256(ground::fore, -1) {}
} fore_256;
struct bg_256 : public color_256 {
bg_256() : color_256(ground::back) {}
bg_256(const short b) : color_256(ground::back, b) {}
bg_256(const bg&) : color_256(ground::back, -1) {}
} back_256;
struct color_16M : public color {
short red, green, blue;
color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
color_16M(ground t, short r, short g, short b) : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
color_16M(ground t, const std::string&) : color(ansi::colors_16M, t) {}
bool is_set() const {return red > -1 and green > -1 and blue > -1;}
std::ostream& print_on( std::ostream&) const {}
};
struct fg_16M : public color_16M {
fg_16M() : color_16M(ground::fore) {}
fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
} fore_16M;
struct bg_16M : public color_16M {
bg_16M() : color_16M(ground::back) {}
bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
} back_16M;
public:
fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
fmt(const short fr, const short fg, const short fb,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
fmt(fg,
const short gr, const short gg, const short gb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
fmt(const short fr, const short fg, const short fb,
bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const short fr, const short fg, const short fb,
typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
fmt(const std::string& f, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
fmt(fg, const std::string& b, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
fmt(const std::string& f, bg, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
fmt(const std::string& f, typo s = typo::none)
: mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
protected:
std::ostream& print_on( std::ostream&) const {}
public:
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;
void operator=(clutchlog const&) = delete;
private:
clutchlog() {}
protected:
struct scope_t {};
scope_t locate(
const level&,
const std::string&,
const std::string&,
const size_t
) const
{}
public:
void format(const std::string&) {}
std::string format() const {}
void format_comment(const std::string&) {}
std::string format_comment() const {}
void out(std::ostream&) {}
std::ostream& out() {}
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
void depth(size_t) {}
size_t depth() const {}
void depth_mark(const std::string) {}
std::string depth_mark() const {}
void strip_calls(const size_t) {}
size_t strip_calls() const {}
#endif
#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_min(const size_t) {}
size_t hfill_min() {}
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&) {}
level threshold() const {}
const std::map<std::string,level> levels() const {}
level level_of(const std::string) {}
void file(std::string) {}
void func(std::string) {}
void line(std::string) {}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
void location(
const std::string&,
const std::string& in_function=".*",
const std::string& in_line=".*"
)
{}
#pragma GCC diagnostic pop
template<class ... FMT>
void style(level, FMT...) {}
void style(level, fmt) {}
fmt style(level) const {}
public:
std::string replace(
const std::string&,
const std::string&,
const std::string&
) const
{}
std::string replace(
const std::string&,
const std::string&,
const size_t
) const
{}
std::string format(
std::string,
const std::string&,
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
const std::string&,
#endif
const level&,
const std::string&,
const std::string&,
const size_t
#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
,
const size_t
#endif
) const
{}
void log(
const level&,
const std::string&,
const std::string&, const std::string&, size_t
) const
{}
template<class In>
void dump(
const level&,
const In, const In,
const std::string&, const std::string&, size_t,
const std::string&,
const std::string
) const
{}
};
#pragma GCC diagnostic pop
#endif // WITH_CLUTCHLOG
#endif // CLUTCHLOG_H
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const std::tuple< fg, bg, typo > &fbs)
Output stream operator for a 3-tuple of 16-colors mode tags.
Definition: clutchlog.h:433
clutchlog::default_depth_mark
static std::string default_depth_mark
Default mark for stack depth.
Definition: clutchlog.h:249
clutchlog::_format_log
std::string _format_log
Current format of the standard output.
Definition: clutchlog.h:913
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:601
clutchlog::depth_styles
void depth_styles(std::vector< fmt > styles)
Set the styles for value-dependant depth formatting.
Definition: clutchlog.h:1045
clutchlog::_level_fmt
std::map< level, fmt > _level_fmt
Dictionary of level identifier to their format.
Definition: clutchlog.h:911
clutchlog::log
void log(const level &stage, const std::string &what, const std::string &file, const std::string &func, size_t line) const
Print a log message IF the location matches the given one.
Definition: clutchlog.h:1356
clutchlog::fmt::back
enum clutchlog::fmt::bg back
Background color.
clutchlog::_funchash_fmts
std::vector< fmt > _funchash_fmts
List of candidate format objects for value-dependant function name styling.
Definition: clutchlog.h:946
clutchlog::fmt::str
std::string str() const
Return the formatting code as a string.
Definition: clutchlog.h:807
clutchlog::fmt::fg_256
Foreground in 256-colors mode.
Definition: clutchlog.h:539
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:1075
clutchlog::fmt::color::operator<<
friend std::ostream & operator<<(std::ostream &os, const color &c)
Print the actually encoded escaped color sequence on the given stream.
Definition: clutchlog.h:493
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const typo &s)
Output stream operator for a typo tag alone, in 16-colors mode.
Definition: clutchlog.h:455
clutchlog::dump_default_format
static std::string dump_default_format
Default format of the comment line in file dump.
Definition: clutchlog.h:235
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:977
clutchlog::fmt::color_16M::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:623
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:659
clutchlog::dump_default_sep
static std::string dump_default_sep
Default item separator for dump.
Definition: clutchlog.h:242
clutchlog::format
std::string format(std::string row, const std::string &what, const level &stage, const std::string &file, const std::string &func, const size_t line) const
Substitute all tags in the format string with the corresponding information and apply the style corre...
Definition: clutchlog.h:1259
clutchlog::fmt::bg_256
Background in 256-colors mode.
Definition: clutchlog.h:556
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Compile-time default mark for stack depth.
Definition: clutchlog.h:246
clutchlog::default_strip_calls
static unsigned int default_strip_calls
Number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:256
clutchlog::default_hfill_min
static size_t default_hfill_min
Default minimum width (number of characters) at which to fill for right-aligning the right part of me...
Definition: clutchlog.h:277
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const std::string &tag) const
Replace mark by tag in form.
Definition: clutchlog.h:1183
clutchlog::fmt::color_256::color_256
color_256(ground t)
Constructor.
Definition: clutchlog.h:518
clutchlog::fmt::back_16M
clutchlog::fmt::bg_16M back_16M
Current background in 16M-colors mode.
clutchlog::fmt::color
Interface class for colors representation.
Definition: clutchlog.h:470
clutchlog::fmt::ansi::colors_16
@ colors_16
16 colors mode.
clutchlog::fmt::bg_16M
background in 256-colors mode.
Definition: clutchlog.h:664
clutchlog::default_hfill_char
static char default_hfill_char
Default character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:263
clutchlog::scope_t::matches
bool matches
Everything is compatible.
Definition: clutchlog.h:1110
clutchlog::fmt::style
enum clutchlog::fmt::typo style
Typographic style.
clutchlog::fmt::color_16M
Abstract base class for 16M colors objects (24-bits ANSI).
Definition: clutchlog.h:573
clutchlog::fmt::fg_256::fg_256
fg_256(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:551
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:972
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:684
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:1071
clutchlog::locate
scope_t locate(const level &stage, const std::string &file, const std::string &func, const size_t line) const
Gather information on the current location of the call.
Definition: clutchlog.h:1132
clutchlog::fmt::fore_16M
clutchlog::fmt::fg_16M fore_16M
Current foreground in 16M-colors mode.
clutchlog::fmt::color_256
Abstract base class for 256 colors objects (8-bits ANSI).
Definition: clutchlog.h:509
clutchlog::fmt::fmt
fmt()
Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:697
clutchlog::style
void style(level stage, fmt style)
Set the style (color and typo) of the given log level, passing a fmt instance.
Definition: clutchlog.h:1096
clutchlog::threshold
void threshold(level l)
Set the log level (below which logs are not printed) with an identifier.
Definition: clutchlog.h:1048
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:1052
clutchlog::fmt::color::is_set
virtual bool is_set() const =0
Should return true if the underying representation encodes an existing color.
clutchlog::_level_short
std::map< level, std::string > _level_short
dictionary of level identifier to their 4-letters representation.
Definition: clutchlog.h:909
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:303
clutchlog::fmt::color_256::color_256
color_256(ground t, const short i)
Constructor.
Definition: clutchlog.h:525
clutchlog::fmt::color_256::print_on
std::ostream & print_on(std::ostream &os) const
Print the color index on the given stream.
Definition: clutchlog.h:531
clutchlog::fmt::color_16M::color_16M
color_16M(ground t)
Constructor.
Definition: clutchlog.h:582
clutchlog::default_hfill_max
static size_t default_hfill_max
Default maximum width (number of characters) for which to fill for right-aligning the right part of m...
Definition: clutchlog.h:275
clutchlog::funchash_styles
void funchash_styles(std::vector< fmt > styles)
Set the candidate styles for value-dependant function name formatting.
Definition: clutchlog.h:1036
clutchlog::scope_t::scope_t
scope_t()
Constructor.
Definition: clutchlog.h:1120
clutchlog::_in_func
std::regex _in_func
Current function location filter.
Definition: clutchlog.h:939
clutchlog::default_format
static std::string default_format
Default format of the messages.
Definition: clutchlog.h:213
clutchlog::fmt::bg_16M::bg_16M
bg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:676
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:296
clutchlog::fmt::fg_16M
Foreground in 256-colors mode.
Definition: clutchlog.h:634
clutchlog::dump
void dump(const level &stage, const In container_begin, const In container_end, const std::string &file, const std::string &func, size_t line, const std::string &filename_template="dump_{n}.dat", const std::string sep=dump_default_sep) const
Dump a serializable container after a comment line with log information.
Definition: clutchlog.h:1381
clutchlog::fmt::fore_256
clutchlog::fmt::fg_256 fore_256
Current foreground in 256-colors mode.
clutchlog::fmt::fore
enum clutchlog::fmt::fg fore
Foreground color.
clutchlog::filehash_styles
void filehash_styles(std::vector< fmt > styles)
Set the candidate styles for value-dependant file name formatting.
Definition: clutchlog.h:1028
clutchlog::fmt::color::type
enum clutchlog::fmt::color::ground type
Type of color (foreground or background).
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:366
clutchlog::fmt::color_256::index
short index
The encoded color index in 4-bits ANSI.
Definition: clutchlog.h:513
clutchlog::fmt::bg_256::bg_256
bg_256()
Empty constructor: no color.
Definition: clutchlog.h:558
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:1073
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:969
clutchlog::_in_file
std::regex _in_file
Current file location filter.
Definition: clutchlog.h:937
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:1094
clutchlog::fmt::bg_256::bg_256
bg_256(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:568
clutchlog::fmt::fg_16M::fg_16M
fg_16M()
Empty constructor: no color.
Definition: clutchlog.h:636
clutchlog::level_of
level level_of(const std::string name)
Return the log level tag corresponding to the given pre-configured name.
Definition: clutchlog.h:1060
clutchlog::_level_word
const std::map< level, std::string > _level_word
Dictionary of level identifier to their string representation.
Definition: clutchlog.h:905
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:795
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:591
clutchlog::fmt::color_16M::print_on
std::ostream & print_on(std::ostream &os) const
Print the color RGB triplet on the given stream.
Definition: clutchlog.h:626
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:411
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Compile-time default format of the messages (debug mode: with absolute location).
Definition: clutchlog.h:198
clutchlog::_in_line
std::regex _in_line
Current line location filter.
Definition: clutchlog.h:941
clutchlog::fmt::fg_256::fg_256
fg_256(const short f)
Constructor.
Definition: clutchlog.h:546
clutchlog::fmt::ansi::colors_256
@ colors_256
256 colors mode.
clutchlog::fmt::mode
enum clutchlog::fmt::ansi mode
Current ANSI color mode.
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const size_t tag) const
Replace mark by tag in form, converting tag to its string representation first.
Definition: clutchlog.h:1248
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:974
clutchlog::fmt::fg_256::fg_256
fg_256()
Empty constructor: no color.
Definition: clutchlog.h:541
clutchlog::fmt::ansi::colors_16M
@ colors_16M
16 millions ("true") colors mode.
clutchlog::_format_dump
std::string _format_dump
Current format of the file output.
Definition: clutchlog.h:915
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Compile-time default item separator for dump.
Definition: clutchlog.h:239
clutchlog::fmt::bg_256::bg_256
bg_256(const short b)
Constructor.
Definition: clutchlog.h:563
clutchlog::fmt::color::ground
ground
Codes for representing foreground or background.
Definition: clutchlog.h:474
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:1108
CLUTCHLOG_DEFAULT_HFILL_MARK
#define CLUTCHLOG_DEFAULT_HFILL_MARK
Character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:260
clutchlog::fmt::print_on
std::ostream & print_on(std::ostream &os) const
Print the currently encoded format escape code on the given output stream.
Definition: clutchlog.h:746
clutchlog::fmt::color_256::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:528
clutchlog::_out
std::ostream * _out
Standard output.
Definition: clutchlog.h:927
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:979
clutchlog::threshold
void threshold(const std::string &l)
Set the log level (below which logs are not printed) with a string.
Definition: clutchlog.h:1050
clutchlog::fmt::color::print_on
virtual std::ostream & print_on(std::ostream &os) const =0
Should print the underlying representation on the given stream.
clutchlog::levels
const std::map< std::string, level > & levels() const
Get the map of available log levels string representations toward their identifier....
Definition: clutchlog.h:1054
clutchlog::_strip_calls
size_t _strip_calls
Current number of call stack levels to remove from depth display.
Definition: clutchlog.h:903
clutchlog::scope_t::stage
level stage
Current log level.
Definition: clutchlog.h:1112
clutchlog::scope_t::there
bool there
Location is compatible.
Definition: clutchlog.h:1118
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:654
CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS
Compile-time number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:253
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:780
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:689
clutchlog::fmt::bg_16M::bg_16M
bg_16M()
Empty constructor: no color.
Definition: clutchlog.h:666
clutchlog::_word_level
std::map< std::string, level > _word_level
Dictionary of level string to their identifier.
Definition: clutchlog.h:907
clutchlog::_stage
level _stage
Current log level.
Definition: clutchlog.h:935
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:1098
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:379
clutchlog::location
void location(const std::string &in_file, const std::string &in_function=".*", const std::string &in_line=".*")
Set the regular expressions filtering the location.
Definition: clutchlog.h:1078
CLUTCHLOG_HAVE_UNIX_SYSINFO
#define CLUTCHLOG_HAVE_UNIX_SYSINFO
True if POSIX headers necessary for stack depth management are available.
Definition: clutchlog.h:33
clutchlog::_filehash_fmts
std::vector< fmt > _filehash_fmts
List of candidate format objects for value-dependant file name styling.
Definition: clutchlog.h:944
clutchlog
The single class which holds everything.
Definition: clutchlog.h:177
clutchlog::fmt::ansi
ansi
ANSI code configuring the available number of colors.
Definition: clutchlog.h:369
clutchlog::fmt::fg_16M::fg_16M
fg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:646
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:390
clutchlog::fmt::color_16M::red
short red
The encoded RGB indices.
Definition: clutchlog.h:577
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Compile-time default format of the comment line in file dump.
Definition: clutchlog.h:221
clutchlog::fmt::color::color
color(ansi a, ground g)
Constructor.
Definition: clutchlog.h:484
clutchlog::fmt::back_256
clutchlog::fmt::bg_256 back_256
Current background in 256-colors mode.