nestlog: control indent level + args with scope entry
This commit is contained in:
parent
49f8acfabb
commit
5ad143d5b6
6 changed files with 98 additions and 50 deletions
|
|
@ -2,28 +2,33 @@
|
|||
|
||||
#include "nestlog/scope.hpp"
|
||||
|
||||
using namespace xo;
|
||||
|
||||
int
|
||||
fib(int n) {
|
||||
XO_SCOPE(log);
|
||||
scope log(XO_SSETUP0(), ":n ", n);
|
||||
|
||||
int retval = 1;
|
||||
|
||||
if (n >= 2) {
|
||||
log(":n ", n);
|
||||
retval = fib(n - 1) + fib(n - 2);
|
||||
log(":n ", n);
|
||||
}
|
||||
|
||||
log(":n ", n, " -> :retval ", retval);
|
||||
log("<- :retval ", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char ** argv) {
|
||||
XO_SCOPE(log);
|
||||
log_config::indent_width = 4;
|
||||
|
||||
int n = 4;
|
||||
|
||||
scope log(XO_SSETUP0(), ":n", 4);
|
||||
|
||||
int fn = fib(n);
|
||||
|
||||
log(":n ", n, " :fib(n) ", fn);
|
||||
log(":n ", n);
|
||||
log("<- :fib(n) ", fn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "log_config.hpp"
|
||||
#include "log_streambuf.hpp"
|
||||
#include "pad.hpp"
|
||||
#include <ostream>
|
||||
#include <memory> // for std::unique_ptr
|
||||
|
||||
|
|
@ -44,11 +46,12 @@ namespace xo {
|
|||
/* common implementation for .preamble(), .postamble() */
|
||||
void entryexit_aux(std::string_view name1,
|
||||
std::string_view name2,
|
||||
char label_char);
|
||||
char label_char,
|
||||
bool newline_flag);
|
||||
|
||||
private:
|
||||
/* current nesting level for this thread */
|
||||
uint32_t nesting_level_ = 0;
|
||||
std::uint32_t nesting_level_ = 0;
|
||||
|
||||
/* buffer space for logging
|
||||
* (before pretty-printing for scope::log() calls that span multiple lines)
|
||||
|
|
@ -95,16 +98,20 @@ namespace xo {
|
|||
#endif
|
||||
|
||||
/* indent to nesting level */
|
||||
this->ss_ << pad(this->nesting_level_ * log_config::indent_width, pad_char);
|
||||
#ifdef OBSOLETE
|
||||
for(uint32_t i = 0, n = this->nesting_level_; i<n; ++i) {
|
||||
this->ss_ << pad_char;
|
||||
}
|
||||
#endif
|
||||
} /*indent*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
void
|
||||
state_impl<CharT, Traits>::entryexit_aux(std::string_view name1,
|
||||
std::string_view name2,
|
||||
char label_char)
|
||||
char label_char,
|
||||
bool newline_flag)
|
||||
{
|
||||
log_streambuf_type * sbuf = this->p_sbuf_phase1_.get();
|
||||
|
||||
|
|
@ -115,7 +122,10 @@ namespace xo {
|
|||
this->ss_ << label_char;
|
||||
|
||||
/* scope name */
|
||||
this->ss_ << name1 << name2 << "\n";
|
||||
this->ss_ << name1 << name2;
|
||||
|
||||
if (newline_flag)
|
||||
this->ss_ << "\n";
|
||||
} /*entryexit_aux*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -123,7 +133,7 @@ namespace xo {
|
|||
state_impl<CharT, Traits>::preamble(std::string_view name1,
|
||||
std::string_view name2)
|
||||
{
|
||||
this->entryexit_aux(name1, name2, '+' /*label_char*/);
|
||||
this->entryexit_aux(name1, name2, '+' /*label_char*/, false /*!newline_flag*/);
|
||||
} /*preamble*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
@ -131,7 +141,7 @@ namespace xo {
|
|||
state_impl<CharT, Traits>::postamble(std::string_view name1,
|
||||
std::string_view name2)
|
||||
{
|
||||
this->entryexit_aux(name1, name2, '-' /*label_char*/);
|
||||
this->entryexit_aux(name1, name2, '-' /*label_char*/, true /*newline_flag*/);
|
||||
} /*postamble*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring> // e.g. for std::memcpy()
|
||||
#include <cassert> // e.g. for std::memcpy()
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
namespace xo {
|
||||
/* recycling buffer for logging.
|
||||
|
|
|
|||
|
|
@ -3,36 +3,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
/* use:
|
||||
* ostream os = ...;
|
||||
*
|
||||
* 1.
|
||||
* os << ":" << pad(8) << ":"
|
||||
*
|
||||
* writes
|
||||
* : :
|
||||
*
|
||||
* 2.
|
||||
* os << pad(16, '-')
|
||||
*
|
||||
* writes
|
||||
* ----------------
|
||||
*
|
||||
* on os
|
||||
*/
|
||||
class pad_impl {
|
||||
public:
|
||||
pad_impl(int32_t n) : n_pad_(n) {}
|
||||
pad_impl(std::uint32_t n, char pad_char) : n_pad_{n}, pad_char_{pad_char} {}
|
||||
|
||||
uint32_t n_pad() const { return n_pad_; }
|
||||
std::uint32_t n_pad() const { return n_pad_; }
|
||||
char pad_char() const { return pad_char_; }
|
||||
|
||||
private:
|
||||
uint32_t n_pad_ = 0;
|
||||
std::uint32_t n_pad_ = 0;
|
||||
char pad_char_ = '\0';
|
||||
}; /*pad_impl*/
|
||||
|
||||
inline pad_impl
|
||||
pad(uint32_t n) { return pad_impl(n); }
|
||||
pad(std::uint32_t n, char pad_char = ' ') { return pad_impl(n, pad_char); }
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &s,
|
||||
pad_impl const &pad)
|
||||
operator<<(std::ostream & s,
|
||||
pad_impl const & pad)
|
||||
{
|
||||
for(uint32_t i=0; i<pad.n_pad(); ++i)
|
||||
s << " ";
|
||||
for(std::uint32_t i=0; i<pad.n_pad(); ++i)
|
||||
s << pad.pad_char();
|
||||
return s;
|
||||
} /*operator<<*/
|
||||
|
||||
|
|
|
|||
|
|
@ -15,15 +15,34 @@ namespace xo {
|
|||
template <typename ChartT, typename Traits>
|
||||
class state_impl;
|
||||
|
||||
//# define XO_SSETUP0() xo::scope_setup(__FUNCTION__)
|
||||
# define XO_SSETUP0() xo::scope_setup(__PRETTY_FUNCTION__)
|
||||
|
||||
/* throw exception if condition not met*/
|
||||
# define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); }
|
||||
/* establish scope using current function name */
|
||||
# define XO_SCOPE(name) xo::scope name(__FUNCTION__)
|
||||
# define XO_SCOPE(name) xo::scope name(xo::scope_setup(__FUNCTION__))
|
||||
/* like XO_SCOPE(name), but also set enabled flag */
|
||||
# define XO_SCOPE2(name, debug_flag) xo::scope name(__FUNCTION__, debug_flag)
|
||||
# define XO_SCOPE_DISABLED(name) xo::scope name(__FUNCTION__, false)
|
||||
# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(__FUNCTION__, debug_flag))
|
||||
# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(__FUNCTION__, false))
|
||||
# define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); }
|
||||
|
||||
/* convenience class for basic_scope<..> construction (see below).
|
||||
* use to disambiguate setup from other arguments
|
||||
*/
|
||||
struct scope_setup {
|
||||
scope_setup(std::string_view name1, std::string_view name2, bool enabled_flag)
|
||||
: name1_{name1}, name2_{name2}, enabled_flag_{enabled_flag} {}
|
||||
scope_setup(std::string_view name1, bool enabled_flag)
|
||||
: scope_setup(name1, "", enabled_flag) {}
|
||||
scope_setup(std::string_view name1)
|
||||
: scope_setup(name1, true /*enabled_flag*/) {}
|
||||
|
||||
std::string_view name1_ = "<.name1>";
|
||||
std::string_view name2_ = "<.name2>";
|
||||
bool enabled_flag_ = false;
|
||||
}; /*scope_setup*/
|
||||
|
||||
/* nesting logger
|
||||
*
|
||||
* Use:
|
||||
|
|
@ -64,9 +83,9 @@ namespace xo {
|
|||
using state_impl_type = state_impl<CharT, Traits>;
|
||||
|
||||
public:
|
||||
basic_scope(std::string_view name1);
|
||||
basic_scope(std::string_view name1, bool enabled_flag);
|
||||
basic_scope(std::string_view name1, std::string_view name2, bool enabled_flag);
|
||||
//basic_scope(std::string_view name1, bool enabled_flag);
|
||||
template <typename... Tn>
|
||||
basic_scope(scope_setup setup, Tn&&... rest);
|
||||
~basic_scope();
|
||||
|
||||
bool enabled() const { return !finalized_; }
|
||||
|
|
@ -76,6 +95,8 @@ namespace xo {
|
|||
/* report current nesting level */
|
||||
std::uint32_t nesting_level() const;
|
||||
|
||||
void set_dest_sbuf(std::streambuf * x) { this->dest_sbuf_ = x; }
|
||||
|
||||
template<typename... Tn>
|
||||
bool log(Tn&&... rest) {
|
||||
if(this->finalized_) {
|
||||
|
|
@ -86,7 +107,7 @@ namespace xo {
|
|||
/* log to per-thread stream to prevent data races */
|
||||
tosn(logstate2stream(logstate), rest...);
|
||||
|
||||
this->flush2clog(logstate);
|
||||
this->flush2sbuf(logstate);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -112,12 +133,14 @@ namespace xo {
|
|||
static std::ostream & logstate2stream(state_impl_type * logstate);
|
||||
|
||||
/* write collected output to std::clog, or chosen streambuf */
|
||||
void flush2clog(state_impl_type * logstate, std::streambuf * p_sbuf = std::clog.rdbuf());
|
||||
void flush2sbuf(state_impl_type * logstate);
|
||||
|
||||
private:
|
||||
/* keep logging state separately for each thread */
|
||||
static thread_local std::unique_ptr<state_impl_type> s_threadlocal_state;
|
||||
|
||||
/* send indented output to this streambuf (e.g. std::clog.rdbuf()) */
|
||||
std::streambuf * dest_sbuf_ = std::clog.rdbuf();
|
||||
/* name of this scope (part 1) */
|
||||
std::string_view name1_ = "<name1>";
|
||||
/* name of this scope (part 2) */
|
||||
|
|
@ -127,17 +150,20 @@ namespace xo {
|
|||
}; /*basic_scope*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
basic_scope<CharT, Traits>::basic_scope(std::string_view fn1,
|
||||
std::string_view fn2,
|
||||
bool enabled_flag)
|
||||
: name1_(fn1),
|
||||
name2_(fn2),
|
||||
finalized_(!enabled_flag)
|
||||
template <typename... Tn>
|
||||
basic_scope<CharT, Traits>::basic_scope(scope_setup setup, Tn&&... args)
|
||||
|
||||
: name1_{std::move(setup.name1_)},
|
||||
name2_{std::move(setup.name2_)},
|
||||
finalized_{!setup.enabled_flag_}
|
||||
{
|
||||
if(enabled_flag) {
|
||||
if(setup.enabled_flag_) {
|
||||
state_impl_type * logstate = basic_scope::require_thread_local_state();
|
||||
|
||||
logstate->preamble(this->name1_, this->name2_);
|
||||
|
||||
tosn(logstate2stream(logstate), " ", args...);
|
||||
|
||||
logstate->flush2sbuf(std::clog.rdbuf());
|
||||
|
||||
///* next call to scope::log() can reset to beginning of buffer space */
|
||||
|
|
@ -147,16 +173,6 @@ namespace xo {
|
|||
}
|
||||
} /*ctor*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
basic_scope<CharT, Traits>::basic_scope(std::string_view fn1, bool enabled_flag)
|
||||
: basic_scope(fn1, "", enabled_flag)
|
||||
{}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
basic_scope<CharT, Traits>::basic_scope(std::string_view fn)
|
||||
: basic_scope(fn, true /*enabled_flag*/)
|
||||
{}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
basic_scope<CharT, Traits>::~basic_scope() {
|
||||
if(!this->finalized_)
|
||||
|
|
@ -205,11 +221,10 @@ namespace xo {
|
|||
|
||||
template <typename CharT, typename Traits>
|
||||
void
|
||||
basic_scope<CharT, Traits>::flush2clog(state_impl_type * logstate,
|
||||
std::streambuf * p_sbuf)
|
||||
basic_scope<CharT, Traits>::flush2sbuf(state_impl_type * logstate)
|
||||
{
|
||||
logstate->flush2sbuf(p_sbuf);
|
||||
} /*flush2clog*/
|
||||
logstate->flush2sbuf(this->dest_sbuf_);
|
||||
} /*flush2sbuf*/
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
void
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ namespace xo {
|
|||
* desired ctor
|
||||
*/
|
||||
|
||||
/* no-op terminal case */
|
||||
template<class Stream>
|
||||
Stream & tos(Stream & s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// Use:
|
||||
// tos(s,a,b,c)
|
||||
// is the same as
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue