nestlog: + terminal colors for entry/exit/code location
This commit is contained in:
parent
f7882b1ff2
commit
fd2be2a4ae
6 changed files with 265 additions and 12 deletions
56
include/nestlog/code_location.hpp
Normal file
56
include/nestlog/code_location.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* @file code_location.hpp */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filename.hpp"
|
||||
#include "color.hpp"
|
||||
|
||||
namespace xo {
|
||||
/* Example:
|
||||
* os << code_location("/path/to/foo.cpp", 123)
|
||||
* writes
|
||||
* foo.cpp:123
|
||||
* on stream os
|
||||
*/
|
||||
|
||||
/* Tag to drive header-only expression */
|
||||
template <typename Tag>
|
||||
class code_location_impl {
|
||||
public:
|
||||
code_location_impl(std::string_view file,
|
||||
std::uint32_t line,
|
||||
color_encoding encoding = CE_Ansi,
|
||||
std::uint32_t color = 31 /*red*/)
|
||||
: file_{file}, line_{line}, encoding_{encoding}, color_{color} {}
|
||||
|
||||
void print_code_location(std::ostream & os) const {
|
||||
os << "["
|
||||
<< with_color(encoding_, color_, basename(file_))
|
||||
<< ":"
|
||||
<< line_
|
||||
<< "]";
|
||||
} /*print_code_location*/
|
||||
|
||||
private:
|
||||
/* __FILE__ */
|
||||
std::string_view file_;
|
||||
/* __LINE__ */
|
||||
std::uint32_t line_ = 0;
|
||||
/* color encoding for file,line */
|
||||
color_encoding encoding_ = CE_Ansi;
|
||||
/* color for file,line */
|
||||
std::uint32_t color_ = 0;
|
||||
}; /*code_location_impl*/
|
||||
|
||||
using code_location = code_location_impl<class code_location_impl_tag>;
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os,
|
||||
code_location const & x)
|
||||
{
|
||||
x.print_code_location(os);
|
||||
return os;
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end code_location.hpp */
|
||||
123
include/nestlog/color.hpp
Normal file
123
include/nestlog/color.hpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/* color.hpp */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
//#include <utility> // for std::move
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
enum color_encoding {
|
||||
CE_None,
|
||||
CE_Ansi,
|
||||
CE_Xterm,
|
||||
};
|
||||
|
||||
enum color_flags {
|
||||
CF_None = 0x0,
|
||||
CF_ColorOn = 0x01,
|
||||
CF_Contents = 0x02,
|
||||
CF_ColorOff = 0x04,
|
||||
CF_All = 0x07
|
||||
};
|
||||
|
||||
template <typename Contents>
|
||||
class color_impl {
|
||||
public:
|
||||
color_impl(color_flags flags, color_encoding encoding, std::uint32_t color, Contents && contents)
|
||||
: flags_{flags}, encoding_{encoding}, color_{color}, contents_{std::move(contents)} {}
|
||||
|
||||
std::uint32_t color() const { return color_; }
|
||||
Contents const & contents() const { return contents_; }
|
||||
|
||||
void print(std::ostream & os) const {
|
||||
if ((flags_ & CF_ColorOn) && (color_ > 0)) {
|
||||
switch(encoding_) {
|
||||
case CE_Ansi:
|
||||
os << "\033[" << color_ << "m";
|
||||
break;
|
||||
case CE_Xterm:
|
||||
os << "\033[38;5;" << color_ << "m";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags_ & CF_Contents)
|
||||
os << contents_;
|
||||
|
||||
if ((flags_ & CF_ColorOff) && (color_ > 0))
|
||||
os << "\033[0m";
|
||||
} /*print*/
|
||||
|
||||
private:
|
||||
color_flags flags_ = CF_None;
|
||||
|
||||
color_encoding encoding_ = CE_Ansi;
|
||||
/* .encoding = CE_Ansi:
|
||||
* 0 = no color
|
||||
* 30 = black
|
||||
* 31 = red
|
||||
* 32 = green
|
||||
* 33 = yellow
|
||||
* 34 = blue
|
||||
* 35 = magenta
|
||||
* 36 = cyan
|
||||
*
|
||||
* .encoding = CE_Xterm:
|
||||
* see [[https://i.stack.imgur.com/KTSQa.png]]
|
||||
* 0..7 standard colors (muted: grey, red, green, yellow, blue, pink, cyan, white)
|
||||
* 8..15 high-intensity colors (grey, red, green, yellow, blue, pink, cyan, white)
|
||||
* 16..51 chooses hue
|
||||
* 16..51 + (0..5)x36 increases whiteness
|
||||
*/
|
||||
std::uint32_t color_ = 0;
|
||||
|
||||
Contents contents_;
|
||||
}; /*color_impl*/
|
||||
|
||||
template <typename Contents>
|
||||
color_impl<Contents> with_ansi_color(std::uint32_t color, Contents && contents) {
|
||||
return color_impl<Contents>(CF_All, CE_Ansi, color, std::move(contents));
|
||||
} /*with_ansi_color*/
|
||||
|
||||
template <typename Contents>
|
||||
color_impl<Contents> with_xterm_color(std::uint32_t color, Contents && contents) {
|
||||
return color_impl<Contents>(CF_All, CE_Xterm, color, std::move(contents));
|
||||
} /*with_ansi_color*/
|
||||
|
||||
template <typename Contents>
|
||||
color_impl<Contents> with_color(color_encoding encoding, std::uint32_t color, Contents && contents) {
|
||||
return color_impl<Contents>(CF_All, encoding, color, std::move(contents));
|
||||
} /*with_color*/
|
||||
|
||||
inline color_impl<int>
|
||||
color_on_ansi(std::uint32_t color) {
|
||||
return color_impl<int>(CF_ColorOn, CE_Ansi, color, 0);
|
||||
} /*color_on_ansi*/
|
||||
|
||||
inline color_impl<int>
|
||||
color_on_xterm(std::uint32_t color) {
|
||||
return color_impl<int>(CF_ColorOn, CE_Xterm, color, 0);
|
||||
} /*color_on_xterm*/
|
||||
|
||||
inline color_impl<int>
|
||||
color_on(color_encoding encoding, std::uint32_t color) {
|
||||
return color_impl<int>(CF_ColorOn, encoding, color, 0);
|
||||
} /*color_on*/
|
||||
|
||||
inline color_impl<int>
|
||||
color_off() {
|
||||
/* any non-zero value works here for color */
|
||||
return color_impl<int>(CF_ColorOff, CE_None, 1 /*color*/, 0);
|
||||
} /*color_off*/
|
||||
|
||||
template <typename Contents>
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, color_impl<Contents> const & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
} /*operator<<*/
|
||||
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end color.hpp */
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
/* @file function.hpp */
|
||||
|
||||
#include "color.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
|
|
@ -19,11 +21,19 @@ namespace xo {
|
|||
template <typename Tag>
|
||||
class function_name_impl {
|
||||
public:
|
||||
/* color: ANSI escape color (lookup Select Graphic Rendition subset)
|
||||
* 0 = none
|
||||
* 31 = red
|
||||
*/
|
||||
function_name_impl(function_style style,
|
||||
std::string_view pretty)
|
||||
: style_{style}, pretty_{pretty} {}
|
||||
color_encoding encoding,
|
||||
std::uint32_t color,
|
||||
std::string_view pretty)
|
||||
: style_{style}, encoding_{encoding}, color_{color}, pretty_{pretty} {}
|
||||
|
||||
function_style style() const { return style_; }
|
||||
color_encoding encoding() const { return encoding_; }
|
||||
std::uint32_t color() const { return color_; }
|
||||
std::string_view const & pretty() const { return pretty_; }
|
||||
|
||||
/* e.g.
|
||||
|
|
@ -152,11 +162,16 @@ namespace xo {
|
|||
if (ch == '>' || ch == ')')
|
||||
--nesting_level;
|
||||
}
|
||||
|
||||
} /*print_aux*/
|
||||
|
||||
private:
|
||||
/* FS_Simple | FS_Pretty (= FS_Literal) | FS_Streamlined */
|
||||
function_style style_;
|
||||
/* CE_Ansi | CE_Xterm */
|
||||
color_encoding encoding_;
|
||||
/* color, if non-zero */
|
||||
std::uint32_t color_;
|
||||
/* e.g. __PRETTY_FUNCTION__ */
|
||||
std::string_view pretty_;
|
||||
}; /*function_name_impl*/
|
||||
|
|
@ -167,19 +182,25 @@ namespace xo {
|
|||
operator<<(std::ostream & os,
|
||||
function_name const & fn)
|
||||
{
|
||||
/* set text color */
|
||||
|
||||
switch(fn.style()) {
|
||||
case FS_Literal:
|
||||
os << fn.pretty();
|
||||
os << with_color(fn.encoding(), fn.color(), fn.pretty());
|
||||
break;
|
||||
case FS_Pretty:
|
||||
os << "[" << fn.pretty() << "]";
|
||||
os << "[" << with_color(fn.encoding(), fn.color(), fn.pretty()) << "]";
|
||||
break;
|
||||
case FS_Simple:
|
||||
os << color_on(fn.encoding(), fn.color());
|
||||
function_name::print_simple(os, fn.pretty());
|
||||
os << color_off();
|
||||
break;
|
||||
case FS_Streamlined:
|
||||
/* omit namespace qualifiers and template arguments */
|
||||
os << color_on(fn.encoding(), fn.color());
|
||||
function_name::print_streamlined(os, fn.pretty());
|
||||
os << color_off();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "function.hpp"
|
||||
#include "nestlog/color.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -13,10 +14,19 @@ namespace xo {
|
|||
static std::uint32_t indent_width;
|
||||
/* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */
|
||||
static function_style style;
|
||||
/* color encoding */
|
||||
static color_encoding encoding;
|
||||
/* color to use for function name, on entry/exit (xo::scope creation/destruction)
|
||||
* (ansi color codes, see Select Graphics Rendition subset)
|
||||
*/
|
||||
static std::uint32_t function_entry_color;
|
||||
static std::uint32_t function_exit_color;
|
||||
/* if true, append [file:line] to output */
|
||||
static bool location_enabled;
|
||||
/* when .location_enabled, write [file:line] starting this many chars from left margin */
|
||||
static std::uint32_t location_tab;
|
||||
/* color to use for code location */
|
||||
static std::uint32_t code_location_color;
|
||||
}; /*log_config_impl*/
|
||||
|
||||
template <typename Tag>
|
||||
|
|
@ -27,6 +37,18 @@ namespace xo {
|
|||
function_style
|
||||
log_config_impl<Tag>::style = FS_Streamlined;
|
||||
|
||||
template <typename Tag>
|
||||
color_encoding
|
||||
log_config_impl<Tag>::encoding = CE_Ansi;
|
||||
|
||||
template <typename Tag>
|
||||
std::uint32_t
|
||||
log_config_impl<Tag>::function_entry_color = 34;
|
||||
|
||||
template <typename Tag>
|
||||
std::uint32_t
|
||||
log_config_impl<Tag>::function_exit_color = 32;
|
||||
|
||||
template <typename Tag>
|
||||
bool
|
||||
log_config_impl<Tag>::location_enabled = true;
|
||||
|
|
@ -35,6 +57,10 @@ namespace xo {
|
|||
std::uint32_t
|
||||
log_config_impl<Tag>::location_tab = 80;
|
||||
|
||||
template <typename Tag>
|
||||
std::uint32_t
|
||||
log_config_impl<Tag>::code_location_color = 31;
|
||||
|
||||
using log_config = log_config_impl<class log_config_tag>;
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,17 @@
|
|||
#include "log_streambuf.hpp"
|
||||
#include "pad.hpp"
|
||||
#include "filename.hpp"
|
||||
#include "code_location.hpp"
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <memory> // for std::unique_ptr
|
||||
|
||||
namespace xo {
|
||||
enum EntryExit {
|
||||
EE_Entry,
|
||||
EE_Exit
|
||||
};
|
||||
|
||||
// track per-thread state associated with nesting logger
|
||||
//
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -55,7 +61,7 @@ namespace xo {
|
|||
void entryexit_aux(function_style style,
|
||||
std::string_view name1,
|
||||
std::string_view name2,
|
||||
char label_char);
|
||||
EntryExit entryexit);
|
||||
|
||||
private:
|
||||
/* current nesting level for this thread */
|
||||
|
|
@ -129,21 +135,37 @@ namespace xo {
|
|||
state_impl<CharT, Traits>::entryexit_aux(function_style style,
|
||||
std::string_view name1,
|
||||
std::string_view name2,
|
||||
char label_char)
|
||||
EntryExit entryexit)
|
||||
{
|
||||
log_streambuf_type * sbuf = this->p_sbuf_phase1_.get();
|
||||
|
||||
sbuf->reset_stream();
|
||||
this->indent(' ');
|
||||
|
||||
char ee_label = '\0';
|
||||
std::uint32_t fn_color = 0;
|
||||
|
||||
color_encoding encoding = log_config::encoding;
|
||||
|
||||
/* mnemonic for scope entry/exit */
|
||||
this->ss_ << label_char;
|
||||
switch(entryexit) {
|
||||
case EE_Entry:
|
||||
ee_label = '+';
|
||||
fn_color = log_config::function_entry_color;
|
||||
break;
|
||||
case EE_Exit:
|
||||
ee_label = '-';
|
||||
fn_color = log_config::function_exit_color;
|
||||
break;
|
||||
}
|
||||
|
||||
this->ss_ << ee_label;
|
||||
|
||||
if (log_config::indent_width > 1)
|
||||
this->ss_ << ' ';
|
||||
|
||||
/* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */
|
||||
this->ss_ << function_name(style, name1) << name2;
|
||||
this->ss_ << function_name(style, encoding, fn_color, name1) << name2;
|
||||
} /*entryexit_aux*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -152,7 +174,7 @@ namespace xo {
|
|||
std::string_view name1,
|
||||
std::string_view name2)
|
||||
{
|
||||
this->entryexit_aux(style, name1, name2, '+' /*label_char*/);
|
||||
this->entryexit_aux(style, name1, name2, EE_Entry);
|
||||
} /*preamble*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -161,7 +183,7 @@ namespace xo {
|
|||
std::string_view name1,
|
||||
std::string_view name2)
|
||||
{
|
||||
this->entryexit_aux(style, name1, name2, '-' /*label_char*/);
|
||||
this->entryexit_aux(style, name1, name2, EE_Exit);
|
||||
} /*postamble*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -241,7 +263,8 @@ namespace xo {
|
|||
sbuf2->sputc(' ');
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "[" << basename(this->file_) << ":" << this->line_ << "]";
|
||||
ss << code_location(this->file_, this->line_,
|
||||
log_config::encoding, log_config::code_location_color);
|
||||
|
||||
std::string ss_str = std::move(ss.str()); /*c++20*/
|
||||
sbuf2->sputn(ss_str.c_str(), ss_str.size());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue